NetBSD Problem Report #60289
From Manuel.Bouyer@lip6.fr Sat May 23 18:41:20 2026
Return-Path: <Manuel.Bouyer@lip6.fr>
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 "R13" (not verified))
by mollari.NetBSD.org (Postfix) with ESMTPS id 901621A923C
for <gnats-bugs@gnats.NetBSD.org>; Sat, 23 May 2026 18:41:20 +0000 (UTC)
Message-Id: <20260523183457.4F6F910E85@armandeche.soc.lip6.fr>
Date: Sat, 23 May 2026 20:34:57 +0200 (CEST)
From: Manuel.Bouyer@lip6.fr
Reply-To: Manuel.Bouyer@lip6.fr
To: gnats-bugs@NetBSD.org
Subject: NetBSD 11 gcc mis-optimises some NULL checks
X-Send-Pr-Version: 3.95
X-From4GNATS: "Manuel.Bouyer@lip6.fr via gnats" <gnats-admin@NetBSD.org>
>Number: 60289
>Category: toolchain
>Synopsis: NetBSD 11 gcc mis-optimises some NULL checks
>Confidential: no
>Severity: serious
>Priority: high
>Responsible: toolchain-manager
>State: analyzed
>Class: sw-bug
>Submitter-Id: net
>Arrival-Date: Sat May 23 18:45:00 +0000 2026
>Closed-Date:
>Last-Modified: Wed Jun 03 18:25:03 +0000 2026
>Originator: Manuel Bouyer
>Release: NetBSD 11.0_RC4
>Organization:
>Environment:
System: NetBSD armandeche.soc.lip6.fr 10.1_STABLE NetBSD 10.1_STABLE (GENERIC_CAN) #36: Mon Oct 13 12:20:13 CEST 2025 bouyer@armandeche.soc.lip6.fr:/local/armandeche1/tmp/build/amd64/obj/local/armandeche2/netbsd-10/src/sys/arch/amd64/compile/GENERIC_CAN amd64
Architecture: x86_64
Machine: amd64
>Description:
I tried updating a server from 10.1_STABLE to 11.0_RC4 and got a
panic within minutes, related to a NULL pointer dereference.
The issue is in ipf_fastroute(), but the code looks good and
dissasembly shows that gcc dropped a NULL pointer check.
I've been able to reproduce it with a simple test funtion (see
How-To-Repeat). It seems that construct like
if (fdp != &fr->fr_dif)
causes gcc to assume (wrongly) that fr cannot be NULL.
This happens at -O2 or highter, -O1 produces the expected code.
>How-To-Repeat:
cat > test-misopt.h << EOF
typedef struct foo {
void *fp;
} foo_t;
typedef struct bar {
void *bp;
foo_t foo;
int flags;
} bar_t;
void testf(foo_t *, bar_t *);
EOF
cat > test-misopt.c << EOF
#include <stdio.h>
#include "test-misopt.h"
void
testf(foo_t *foop, bar_t *barp)
{
if (&barp->foo != foop) {
printf("A ");
if (!barp || !(barp->flags & 0x01)) {
printf("B ");
}
printf("C ");
}
printf("D\n");
}
EOF
/home/build/amd64/obj/netbsd-11/tooldir/bin/x86_64--netbsd-gcc -g -c -O2 test-misopt.c
gdb -ex "disas /s testf" test-misopt.o
and notice:
10 if (!barp || !(barp->flags & 0x01)) {
0x0000000000000021 <+33>: testb $0x1,0x10(%rbx)
0x0000000000000025 <+37>: je 0x4d <testf+77>
%rsi or %rbx is never tested for 0.
>Fix:
#pragma GCC optimize ("O1")
before the affected funtion works around it
But this behavior is worrisome
>Release-Note:
>Audit-Trail:
From: Christos Zoulas <christos@zoulas.com>
To: gnats-bugs@netbsd.org
Cc: toolchain-manager@netbsd.org,
gnats-admin@netbsd.org,
netbsd-bugs@netbsd.org
Subject: Re: toolchain/60289: NetBSD 11 gcc mis-optimises some NULL checks
Date: Sat, 23 May 2026 16:28:06 -0400
--Apple-Mail=_C0AD64E4-92BB-4398-B39F-BD45041F0A5F
Content-Transfer-Encoding: 7bit
Content-Type: text/plain;
charset=us-ascii
&barp->foo is UB if barp is NULL, so the compiler skips the next test.
This is what the language lawyers have decided.
christos
--Apple-Mail=_C0AD64E4-92BB-4398-B39F-BD45041F0A5F
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment;
filename=signature.asc
Content-Type: application/pgp-signature;
name=signature.asc
Content-Description: Message signed with OpenPGP
-----BEGIN PGP SIGNATURE-----
Comment: GPGTools - http://gpgtools.org
iF0EARECAB0WIQS+BJlbqPkO0MDBdsRxESqxbLM7OgUCahIN1wAKCRBxESqxbLM7
OpbzAJ4qmEjMbRrRgT0u0M3GUTAWthHaNwCgxVqqZQFBPCzyeG3v/j1NQYn5Q0s=
=zWhX
-----END PGP SIGNATURE-----
--Apple-Mail=_C0AD64E4-92BB-4398-B39F-BD45041F0A5F--
State-Changed-From-To: open->analyzed
State-Changed-By: riastradh@NetBSD.org
State-Changed-When: Sat, 23 May 2026 21:59:11 +0000
State-Changed-Why:
This actually may be a gcc bug, because we compile the kernel with
-fno-delete-null-pointer-checks, which is supposed to prevent gcc from
eliminating these checks:
https://nxr.netbsd.org/xref/src/sys/conf/Makefile.kern.inc?r=1.306#108
https://gcc.gnu.org/onlinedocs/gcc-14.3.0/gcc/Optimize-Options.html#index-fdelete-null-pointer-checks
It's not NetBSD-specific -- here's a godbolt.org example with 14.3.0,
presumably not on NetBSD:
https://godbolt.org/z/aT6xqdMer
.LC0:
.string "A "
...
mov edi, OFFSET FLAT:.LC0
call printf
test BYTE PTR [rbx+16], 1
je .L9
So I think someone should file a bug with gcc upstream.
In the mean time, we should also fix this idiom and avoid evaluating
&barp->foo when barp might be null -- we did nix some cases of it when
clang found them, but they were slightly different, like this:
https://mail-index.netbsd.org/source-changes/2014/11/06/msg060206.html
> Fix little C issues in i915drmkms hindering the Clang build.
>
> - Test `x == NULL', not `&container_of(x, t, base)->base == NULL'.
> ...
- obj = to_intel_bo(drm_gem_object_lookup(dev, file, args->handle));
- if (&obj->base == NULL)
+ gobj = drm_gem_object_lookup(dev, file, args->handle);
+ if (gobj == NULL)
return -ENOENT;
+ obj = to_intel_bo(gobj);
The null pointer check in _this_ case vanished some time between gcc10
(as shipped in netbsd-10) and gcc11:
https://godbolt.org/z/fT6P66KT4 (gcc 10.5)
mov edi, OFFSET FLAT:.LC0
call printf
test rbx, rbx
je .L3
test BYTE PTR [rbx+16], 1
jne .L4
https://godbolt.org/z/Ee8hW3z37 (gcc 11.5)
mov edi, OFFSET FLAT:.LC0
call printf
test BYTE PTR [rbx+16], 1
je .L9
From: Manuel Bouyer <manuel.bouyer@lip6.fr>
To: gnats-bugs@netbsd.org
Cc: toolchain-manager@netbsd.org, netbsd-bugs@netbsd.org,
gnats-admin@netbsd.org, riastradh@NetBSD.org
Subject: Re: toolchain/60289 (NetBSD 11 gcc mis-optimises some NULL checks)
Date: Sun, 24 May 2026 10:49:30 +0200
On Sat, May 23, 2026 at 09:59:12PM +0000, riastradh@NetBSD.org wrote:
> Synopsis: NetBSD 11 gcc mis-optimises some NULL checks
>
> State-Changed-From-To: open->analyzed
> State-Changed-By: riastradh@NetBSD.org
> State-Changed-When: Sat, 23 May 2026 21:59:11 +0000
> State-Changed-Why:
> This actually may be a gcc bug, because we compile the kernel with
> -fno-delete-null-pointer-checks, which is supposed to prevent gcc from
> eliminating these checks:
>
> https://nxr.netbsd.org/xref/src/sys/conf/Makefile.kern.inc?r=1.306#108
> https://gcc.gnu.org/onlinedocs/gcc-14.3.0/gcc/Optimize-Options.html#index-fdelete-null-pointer-checks
>
> It's not NetBSD-specific -- here's a godbolt.org example with 14.3.0,
> presumably not on NetBSD:
>
> https://godbolt.org/z/aT6xqdMer
>
> .LC0:
> .string "A "
> ...
> mov edi, OFFSET FLAT:.LC0
> call printf
> test BYTE PTR [rbx+16], 1
> je .L9
>
> So I think someone should file a bug with gcc upstream.
I found at last one gcc bug report on this topic:
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=100404
Adding
asm("" : "+r"(barp));
just before the !barp test works around the isssue.
but explicitely checking for NULL before &barp->foo is a more correct
fix, even if it leads to an extra test which is not needed (could an
overly agressive optimisation leading to slower code be considered as a bug ?)
But,
-fno-delete-null-pointer-checks doesn't work in this case; this is a real
problem
It seems that there's no way to get a warning when this optimisation is
triggered, which I think is also a problem for developers.
A quick search showed other projects (bind, openjdk) running into this
--
Manuel Bouyer, LIP6, Sorbonne Université. Manuel.Bouyer@lip6.fr
NetBSD: 26 ans d'experience feront toujours la difference
--
From: RVP <rvp@SDF.ORG>
To: Manuel Bouyer <manuel.bouyer@lip6.fr>
Cc: gnats-bugs@netbsd.org
Subject: Re: toolchain/60289 (NetBSD 11 gcc mis-optimises some NULL checks)
Date: Sun, 24 May 2026 09:10:03 +0000 (UTC)
On Sun, 24 May 2026, Manuel Bouyer wrote:
> A quick search showed other projects (bind, openjdk) running into this
>
This is an old issue, and the gcc devs' response to all the howling on the
Linux side was "Will not fix".
https://lwn.net/Articles/342330/
https://lwn.net/Articles/342420/
-RVP
From: Manuel Bouyer <manuel.bouyer@lip6.fr>
To: RVP <rvp@SDF.ORG>
Cc: gnats-bugs@netbsd.org
Subject: Re: toolchain/60289 (NetBSD 11 gcc mis-optimises some NULL checks)
Date: Sun, 24 May 2026 13:42:46 +0200
On Sun, May 24, 2026 at 09:10:03AM +0000, RVP wrote:
> On Sun, 24 May 2026, Manuel Bouyer wrote:
>
> > A quick search showed other projects (bind, openjdk) running into this
> >
>
> This is an old issue, and the gcc devs' response to all the howling on the
> Linux side was "Will not fix".
>
> https://lwn.net/Articles/342330/
> https://lwn.net/Articles/342420/
OK, but both articles mention -fno-delete-null-pointer-checks to deal with it.
But in the specific case this PR is about, -fno-delete-null-pointer-checks
doens't prevent the optimisation from removing the NULL pointer
check. I think this is a bug in gcc, and none of the article above
mention this issue (and I couldn't find a gcc bug report about it either).
--
Manuel Bouyer, LIP6, Sorbonne Université. Manuel.Bouyer@lip6.fr
NetBSD: 26 ans d'experience feront toujours la difference
--
From: Taylor R Campbell <riastradh@NetBSD.org>
To: RVP <rvp@SDF.ORG>
Cc: gnats-bugs@netbsd.org, toolchain-manager@netbsd.org,
gnats-admin@netbsd.org,
netbsd-bugs@netbsd.org, Manuel.Bouyer@lip6.fr
Subject: Re: toolchain/60289 (NetBSD 11 gcc mis-optimises some NULL checks)
Date: Sun, 24 May 2026 14:43:31 +0000
> Date: Sun, 24 May 2026 09:10:03 +0000 (UTC)
> From: RVP <rvp@SDF.ORG>
>=20
> On Sun, 24 May 2026, Manuel Bouyer wrote:
>=20
> > A quick search showed other projects (bind, openjdk) running into this
>=20
> This is an old issue, and the gcc devs' response to all the howling on the
> Linux side was "Will not fix".
>=20
> https://lwn.net/Articles/342330/
> https://lwn.net/Articles/342420/
The case in https://lwn.net/Articles/342330/ is different for two
reasons:
1. The Linux code quoted there actually dereferences the null pointer
_before_ the check, rather than simply computing an address
indirection.
struct sock *sk =3D tun->sk;
unsigned int mask =3D 0;
if (!tun)
return POLLERR;
Actually dereferencing a null pointer is unambiguously UB without
any involvement of language lawyers. C99, Sec. 6.5.3.2 `Address
and indirection operators', clause 4:
If an invalid value has been assigned to the pointer, the
behavior of the unary * operator is undefined.^87)
87) ... Among the invalid values for dereferencing a pointer by
the unary * operator are a null pointer, ...
In contrast, the code bouyer@ was discussing involves _address of_
a member operator. It would be as if the code were instead:
struct sock **sk =3D &tun->sk;
unsigned int mask =3D 0;
if (!tun)
return POLLERR;
Whether this is UB takes more language-lawyering to argue (and,
e.g., if it is UB, that breaks the traditional definition of
offsetof(T, F) as (size_t)((char *)&((T *)0)->F - (char *)(T *)0)).
2. We are using -fno-delete-null-pointer-checks here. GCC is supposed
to assume _even if_ the pointer is dereferenced, downstream logic
_still_ cannot assume the pointer is nonnull:
-fdelete-null-pointer-checks
Assume that programs cannot safely dereference null
pointers, and that no code or data element resides at
address zero. This option enables simple constant
folding optimizations at all optimization levels. In
addition, other optimization passes in GCC use this
flag to control global dataflow analyses that
eliminate useless checks for null pointers; these
assume that a memory access to address zero always
results in a trap, so that if a pointer is checked
after it has already been dereferenced, it cannot be
null.
Note however that in some environments this assumption
is not true. Use -fno-delete-null-pointer-checks to
disable this optimization for programs that depend on
that behavior.
https://gcc.gnu.org/onlinedocs/gcc-14.3.0/gcc/Optimize-Options.html#index-=
fdelete-null-pointer-checks
If dereferencing the pointer as barp->foo weren't enough to justify
pruning downstream null checks, surely taking the address
&barp->foo shouldn't justify pruning downstream null checks.
From: "Manuel Bouyer" <bouyer@netbsd.org>
To: gnats-bugs@gnats.NetBSD.org
Cc:
Subject: PR/60289 CVS commit: src/sys/external/bsd/ipf/netinet
Date: Sun, 24 May 2026 17:43:18 +0000
Module Name: src
Committed By: bouyer
Date: Sun May 24 17:43:18 UTC 2026
Modified Files:
src/sys/external/bsd/ipf/netinet: ip_fil_netbsd.c
Log Message:
Explicitely check a pointer against NULL before computing a member address,
to avoid undefined behavior. Avoids the same NULL pointer check being
"optimised" later, leading to NULL pointer dereference.
It is expected that -fno-delete-null-pointer-checks would avoid this but
it does not.
For details see
https://mail-index.netbsd.org/tech-toolchain/2026/05/23/msg004818.html
and PR toolchain/60289
Needs pullup to netbsd-11.
To generate a diff of this commit:
cvs rdiff -u -r1.39 -r1.40 src/sys/external/bsd/ipf/netinet/ip_fil_netbsd.c
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
From: "Martin Husemann" <martin@netbsd.org>
To: gnats-bugs@gnats.NetBSD.org
Cc:
Subject: PR/60289 CVS commit: [netbsd-11] src/sys/external/bsd/ipf/netinet
Date: Wed, 3 Jun 2026 18:24:52 +0000
Module Name: src
Committed By: martin
Date: Wed Jun 3 18:24:52 UTC 2026
Modified Files:
src/sys/external/bsd/ipf/netinet [netbsd-11]: ip_fil_netbsd.c
Log Message:
Pull up following revision(s) (requested by bouyer in ticket #295):
sys/external/bsd/ipf/netinet/ip_fil_netbsd.c: revision 1.40
Explicitely check a pointer against NULL before computing a member address,
to avoid undefined behavior. Avoids the same NULL pointer check being
"optimised" later, leading to NULL pointer dereference.
It is expected that -fno-delete-null-pointer-checks would avoid this but
it does not.
For details see
https://mail-index.netbsd.org/tech-toolchain/2026/05/23/msg004818.html
and PR toolchain/60289
To generate a diff of this commit:
cvs rdiff -u -r1.39 -r1.39.4.1 \
src/sys/external/bsd/ipf/netinet/ip_fil_netbsd.c
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
>Unformatted:
(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.