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



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