Subject: bug#69438: basename faulty with nul and suffix

From: Zefram <[email-masked]>
Date: Tue, 27 Feb 2024 20:14:58 +0000

Trying out the basename function in Guile 3.0.9:

scheme@(guile-user)> (basename "foo/bar")
$1 = "bar"
scheme@(guile-user)> (basename "foo/bar" "r")
$2 = "ba"
scheme@(guile-user)> (basename "foo/bar" "x")
$3 = "bar"
scheme@(guile-user)> (basename "foo/bar\0baz/quux")
$4 = "bar"
scheme@(guile-user)> (basename "foo/bar\0baz/quux" "r")
$5 = "bar"
scheme@(guile-user)> (basename "foo/bar\0baz/quux" "x")
$6 = "ba"

The first three cases here show the function operating correctly on a
mundane pathname string.

The fourth case shows it operating in a debatable manner on a pathname
string that has an embedded nul.  This treatment of this case is based
on the idea that the string is acceptable as a pathname for file I/O
functions, and that the nul will serve to terminate the pathname (which
is what happens naturally in a naive treatment of passing the string to
a system call).  I note that the open-file function had that treatment
of embedded nuls in Guile 1.6, but that since Guile 1.8 it has instead
signalled an error on such a pathname string.  Are there any remaining
functions that accept embedded nuls in pathname strings?  If not, then the
basename and dirname functions probably ought to correspondingly signal
an error for an embedded nul.  (Incidentally, basename and dirname had
unambiguously incorrect treatment of embedded nuls prior to Guile 2.0,
so there's never yet been a version in which open-file and basename had
matching treatment of embedded nuls.)

But what I'm really interested in here is the fifth and sixth cases,
where there's an embedded nul in the pathname string and also a suffix
argument.  Accepting the interpretation of the embedded nul as correct,
the treatment here of the suffix is clearly faulty.  Whether the suffix
matches is being incorrectly checked against the original string, before
nul truncation, but the suffix removal is being applied to the correct
basename.  It's possible to give a suffix that matches the untruncated
string but is longer than the true basename, causing the suffix removal
to error due to indexing outside the string.  Whether the suffix matches
should instead be checked against the nul-truncated string.

-zefram