NetBSD Problem Report #60517
From www@netbsd.org Wed Jul 29 17:31:46 2026
Return-Path: <www@netbsd.org>
Received: from mail.netbsd.org (mail.netbsd.org [199.233.217.200])
(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)
key-exchange X25519 server-signature RSA-PSS (2048 bits)
client-signature RSA-PSS (2048 bits))
(Client CN "mail.netbsd.org", Issuer "YR2" (not verified))
by mollari.NetBSD.org (Postfix) with ESMTPS id 00A2B1A923B
for <gnats-bugs@gnats.NetBSD.org>; Wed, 29 Jul 2026 17:31:45 +0000 (UTC)
Message-Id: <20260729173144.AE6241A923C@mollari.NetBSD.org>
Date: Wed, 29 Jul 2026 17:31:44 +0000 (UTC)
From: drew@ddevault.org
Reply-To: drew@ddevault.org
To: gnats-bugs@NetBSD.org
Subject: fnmatch(2) does not implement FNM_PATHNAME correctly
X-Send-Pr-Version: www-1.0
X-From4GNATS: "drew@ddevault.org via gnats" <gnats-admin@NetBSD.org>
>Number: 60517
>Category: lib
>Synopsis: fnmatch(2) does not implement FNM_PATHNAME correctly
>Confidential: no
>Severity: serious
>Priority: medium
>Responsible: lib-bug-people
>State: open
>Class: sw-bug
>Submitter-Id: net
>Arrival-Date: Wed Jul 29 17:35:00 +0000 2026
>Last-Modified: Wed Aug 05 08:35:02 +0000 2026
>Originator: Drew DeVault
>Release: NetBSD 11.0-rc7
>Organization:
>Environment:
NetBSD kludge 11.0_RC7 NetBSD 11.0_RC7 (GENERIC) #0: Wed Jul 22 05:26:24 UTC 2026 mkrepro@mkrepro.NetBSD.org:/usr/src/sys/arch/amd64/compile/GENERIC amd64 x86_64 Intel 686-class NetBSD
>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.
>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);
}
>Audit-Trail:
From: Luke Mewburn <luke@mewburn.net>
To: gnats-bugs@netbsd.org, christos@netbsd.org
Cc: lib-bug-people@netbsd.org, gnats-admin@netbsd.org,
netbsd-bugs@netbsd.org
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 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);
| }
|
From: Christos Zoulas <christos@zoulas.com>
To: Luke Mewburn <luke@mewburn.net>
Cc: gnats-bugs@netbsd.org,
christos@netbsd.org,
lib-bug-people@netbsd.org,
gnats-admin@netbsd.org,
netbsd-bugs@netbsd.org
Subject: Re: lib/60517: fnmatch(2) does not implement FNM_PATHNAME correctly
Date: Wed, 5 Aug 2026 11:34:16 +0300
Yes, I believe the fix is correct and should be committed.
christos
(Contact us)
$NetBSD: query-full-pr,v 1.51 2026/08/10 02:28:17 riastradh Exp $
$NetBSD: gnats_config.sh,v 1.10 2026/05/13 22:00:09 riastradh Exp $
Copyright © 1994-2026
The NetBSD Foundation, Inc. ALL RIGHTS RESERVED.