Moi said:
Strictly speaking it is UB.
But, given the fact that the kernel-source must be considered
freestanding code, IMHO different rules _could_ apply.
( I don't know what GCC's -ffreestanding flag actually does; it possibly
just avoids library dependencies)
IIRC in freestanding environments the compiler *may* define UB to
anything it wants. (correct me if I am wrong)
It's not quite clear what you're saying, but all of the
interpretations I can think of make that statement wrong.
One possibility is that you're talking about the circumstances where
behavior is UB. Those are defined by the C standard (though in some
cases, they are defined only by the absence of a definition for the
behavior). A freestanding implementation of C is not allowed to change
those definitions. However, those definitions impose somewhat fewer
requirements on freestanding implementations than on hosted ones. The
most important differences are that the startup need not be called main
(), and has an implementation-defined interface, and most of the C
standard library becomes optional. None of those differences are
relevant in this context.
Another possibility is that you're referring to the behavior that
actually occurs when the C standard says that the behavior is
undefined. All implementations, freestanding or hosted, have complete
freedom to define such behavior any way they want - that's precisely
what "undefined behavior" means.
I can imagine the compiler user _wants_ the "intended behaviour" (IB) to
be "If I dereference null pointers, I know what I'm doing. Trust me ..."
How else could a kernel ever address memory at location=0 ?
Please note: a null pointer need not refer to location==0, and a
pointer referring to location==0 need not be a null pointer; this is
entirely up to the implementation. Try not to confuse the two
concepts. An integer constant expression with a value of 0, converted
into a pointer, is guaranteed to convert into a null pointer. However,
it's not meaningful, within the C standard, to even talk about which
memory location a null pointer points at; if an implementation chooses
to allow derefencing such pointers, it need not define the resulting
behavior as "refer to the object of the appropriate type residing at
location=0".
How a kernel addresses the memory at location==0 is entirely
implementation-specific; there's no portable way to write such code
(though dereferencing a null pointer probably has that effect on many
platforms). An implementation is not required to provide a way to do
this; if that fact renders it impossible to compile the kernel for a
particular implementation, then you shouldn't use that implementation
to compile the kernel.
Seen in this light, the compiler should *not* be allowed to optimize out
the null-test, since the initialiser does not *test* anything, it just
proves that it did not trap.
It's trivial to fix this code to do what is actually desired.
However, if the kernel developer really feels a need to write
defective code, and to have the compiler produce the desired results
despite the fact that the code is defective, the a different compiler
should have been a used (such as gcc -fno-delete-null-pointer-checks).