Skip to content

nob_get_file_type error check is dead code: nob_copy_directory_recursively aborts and nob_walk_dir returns true on unreadable paths #262

Description

@NeikiDev

nob_get_file_type() returns (Nob_File_Type)-1 to signal failure, but two callers check for that with if (type < 0). Nob_File_Type is an enum with only non-negative enumerators, so the compiler gives it an unsigned underlying type and the < 0 check is always false. The error is never caught.

  • nob__walk_dir_opt_impl() (line 2122): the walk continues with an invalid file_type and nob_walk_dir() returns true for a path that could not be stat-ed.
  • nob_copy_directory_recursively() (line 2328): execution falls through the switch to default: NOB_UNREACHABLE(...), which calls abort(). A missing or unreadable source directory crashes the whole program instead of returning false.

Both compile without warning under gcc -Wall -Wextra and clang -Wall -Wextra.

Repro

#define NOB_IMPLEMENTATION
#include "nob.h"

static bool walk_cb(Nob_Walk_Entry entry)
{
    (void) entry;
    return true;
}

int main(void)
{
    const char *missing = "this-path-does-not-exist";

    // nob_walk_dir() reports success on a path that could not be stat-ed
    bool walk_ok = nob_walk_dir(missing, walk_cb);
    nob_log(NOB_INFO, "nob_walk_dir returned %s", walk_ok ? "true" : "false");

    // nob_copy_directory_recursively() aborts instead of returning false
    bool copy_ok = nob_copy_directory_recursively(missing, "dst");
    nob_log(NOB_INFO, "nob_copy_directory_recursively returned %s", copy_ok ? "true" : "false");

    return 0;
}
$ cc -o poc poc.c && ./poc
[ERROR] Could not get stat of this-path-does-not-exist: No such file or directory
[INFO] nob_walk_dir returned true
[ERROR] Could not get stat of this-path-does-not-exist: No such file or directory
./nob.h:2372: UNREACHABLE: nob_copy_directory_recursively
$ echo $?
134

Reproduced on nob.h v3.10.0 with clang on macOS and gcc 14 on Linux (same output on both).

Potential fix

Compare against the sentinel value instead of < 0, which works whether the enum is signed or unsigned:

-    if (file_type < 0) nob_return_defer(false);
+    if (file_type == (Nob_File_Type)-1) nob_return_defer(false);
-    if (type < 0) return false;
+    if (type == (Nob_File_Type)-1) return false;

With that change nob_copy_directory_recursively() returns false on the missing path and nob_walk_dir() returns false, each after logging the stat error once.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions