NetBSD-Bugs archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

Re: lib/60517: fnmatch(2) does not implement FNM_PATHNAME correctly



The following reply was made to PR lib/60517; it has been noted by GNATS.

From: Luke Mewburn <luke%mewburn.net@localhost>
To: gnats-bugs%netbsd.org@localhost, christos%netbsd.org@localhost
Cc: lib-bug-people%netbsd.org@localhost, gnats-admin%netbsd.org@localhost,
	netbsd-bugs%netbsd.org@localhost
Subject: Re: lib/60517: fnmatch(2) does not implement FNM_PATHNAME correctly
Date: Wed, 5 Aug 2026 18:32:02 +1000

 On 26-07-29 17:35, drew%ddevault.org@localhost via gnats wrote:
   | >Description:
   | fnmatch(3) does not implement FNM_PATHNAME correctly in rangematch,
   | causing some patterns to not match correctly.
   | 
   | >How-To-Repeat:
   | The following program reproduces the issue:
   | 
   | #include <fnmatch.h>
   | #include <stdio.h>
   | 
   | int main(int argc, char *argv[]) {
   | 	int match = fnmatch(argv[1], argv[2], 0);
   | 	printf("%d\n", match);
   | 	return 0;
   | }
   | 
   | Run:
   | 
   | ./fnmatch '[\\/$]*' '/usr/lib'
   | 
   | And it should print 0.
 
 (+ Christos)
 
 Hi Drew,
 
 tl;dr: I think you have identified a bug with fnmatch without FNM_PATHNAME,
 even if I think your test case pattern was a bit tricky at first :)
 
 Unless Christos (or someone else) disagrees with your report
 and my analysis, I think this should be committed.
 
 
 Details:
 
 When I first analyzed your report it wasn't clear what the fault was:
 1. Your pattern was a bit tricky. Now I see that the intention is to
    match any string starting with `\', `/', or `$', relying upon
    `\\' to become `\` because you're not using FNM_NOESCAPE.
 2. You're not using FNM_PATHNAME.
 
 I've dug into the commit that caused the issue, and read multiple
 versions of the relevant POSIX pages, and I now understand your bug
 report and think your proposed fix is correct.
 
 The commit to lib/libc/gen/fnmatch.c 1.26 on 2014-10-12 was by Christos,
 with commit message:
 	Fix fnmatch issues according to POSIX.
 	http://pubs.opengroup.org/onlinepubs/009695399/utilities/xcu_chap02.html#tag_02_13_01
 	1. A [...] pattern containing a slash is not a pattern; the [ ]'s become regular
 	   characters
 	2. A [] or a [!] is not an empty pattern, why would it? The first would never
 	   match and the second would always match which makes it equivalent to ?
 	   In those cases the ] is taken as a literal character and does not have
 	   special meaning.
 
 Reading that POSIX (issue 6) "Shell Command Language" page linked in item 1,
 I don't actually see the text relating to item 1 in section 2.13.1.
 There's related text in section 2.13.3 "Patterns Used for Filename Expansion".
 
 However, the POSIX (issue 6) fnmatch page at
   https://pubs.opengroup.org/onlinepubs/009695399/functions/fnmatch.html 
 doesn't cross-reference back to this shell section 2.13.3 about filename
 expansion.  It seems to me that fnmatch FNM_PATHNAME has a limited and
 different implementation than the shell.
 
 The relevant text in fnmatch for slash without FNM_PATHNAME is:
 	If the FNM_PATHNAME flag is not set, the slash character shall be
 	treated as an ordinary character.
 
 The latest POSIX (issue 8) page for fnmatch at
   https://pubs.opengroup.org/onlinepubs/9799919799/functions/fnmatch.html
 has similar text:
 	If the FNM_PATHNAME flag is not set, the <slash> character shall
 	be treated as an ordinary character.
 
 Regards,
 Luke.
 
 
 
   | >Fix:
   | --- src.orig/lib/libc/gen/fnmatch.c	2014-10-13 00:32:33.000000000 +0200
   | +++ src/lib/libc/gen/fnmatch.c	2026-07-29 15:25:45.271817024 +0200
   | @@ -91,7 +91,7 @@
   |  	need = 1;
   |  	for (ok = 0; (c = FOLDCASE(*pattern++, flags)) != ']' || need;) {
   |  		need = 0;
   | -		if (c == '/')
   | +		if (c == '/' && (flags & FNM_PATHNAME))
   |  			return (void *)-1;
   |  		if (c == '\\' && !(flags & FNM_NOESCAPE))
   |  			c = FOLDCASE(*pattern++, flags);
   | --- src.orig/tests/lib/libc/gen/t_fnmatch.c	2016-10-31 06:08:53.000000000 +0100
   | +++ src/tests/lib/libc/gen/t_fnmatch.c	2026-07-29 19:25:10.723264988 +0200
   | @@ -125,6 +125,8 @@
   |  	ATF_CHECK(fnmatch("???x", "xxxx", FNM_PATHNAME) == 0);
   |  	ATF_CHECK(fnmatch("*/xxx", "/xxx", FNM_PATHNAME) == 0);
   |  	ATF_CHECK(fnmatch("x/*.y", "x/z.y", FNM_PATHNAME) == 0);
   | +
   | +	ATF_CHECK(fnmatch("[\\\\/$]*", "/usr/lib", 0) == 0);
   |  }
   | 
 



Home | Main Index | Thread Index | Old Index