NetBSD-Bugs archive

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

Re: toolchain/60289 (NetBSD 11 gcc mis-optimises some NULL checks)



> Date: Sun, 24 May 2026 09:10:03 +0000 (UTC)
> From: RVP <rvp%SDF.ORG@localhost>
> 
> 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/

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 = tun->sk;
	unsigned int mask = 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 = &tun->sk;
	unsigned int mask = 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.



Home | Main Index | Thread Index | Old Index