Bug 240509 - segfault in basename(3)
Summary: segfault in basename(3)
Status: Closed Not A Bug
Alias: None
Product: Base System
Classification: Unclassified
Component: bin (show other bugs)
Version: 12.0-RELEASE
Hardware: Any Any
: --- Affects Only Me
Assignee: freebsd-bugs mailing list
Depends on:
Reported: 2019-09-11 14:15 UTC by Niclas Zeising
Modified: 2019-09-11 16:26 UTC (History)
1 user (show)

See Also:

reproducer (199 bytes, text/plain)
2019-09-11 14:15 UTC, Niclas Zeising
no flags Details

Note You need to log in before you can comment on or make changes to this bug.
Description Niclas Zeising freebsd_committer 2019-09-11 14:15:19 UTC
Created attachment 207388 [details]

I'm getting a segfault when calling basename(3) on FreeBSD 12.0 and CURRENT.  See attached source for an easy to use reproducer.

This might be a case of "don't do that", but the same code on Linux works.
Comment 1 Mateusz Guzik freebsd_committer 2019-09-11 14:31:44 UTC
basename is allowed to modify the passes buffer. This is documented on both FreeBSD and Linux. In the attached example the string is immutable, an attempt to modify it is undefined behavior and a crash (as observed) the likely outcome.

The FreeBSD implementation happens to always at least add a NUL-byte which triggers the crash here, while Linux one does not modify the string if there is nothing to do.

The program will trivially crash if the string is modified to get basename to operate, e.g. by adding trailing slashes: "/home/tags///".

Finally, the Linux manpage explicitly shows usage with a copied buffer:

       The following code snippet demonstrates the use of basename() and dirname():
           char *dirc, *basec, *bname, *dname;
           char *path = "/etc/passwd";

           dirc = strdup(path);
           basec = strdup(path);
           dname = dirname(dirc);
           bname = basename(basec);
           printf("dirname=%s, basename=%s\n", dname, bname);

That said, there is no bug in the FreeBSD version and the code does not crash on Linux because of a combination of an artifact of the implementation and the passed argument. FreeBSD variant can be modified to match but there is real benefit to it.