[llvm-dev] Calling a null pointer. How undefined it is?

mats petersson via llvm-dev llvm-dev at lists.llvm.org
Tue Jun 14 02:06:12 PDT 2016


Undefined behaviour is not guaranteed to cause a stop. It's just "do
something that may or may not be what you expected". Yes, most operating
systems prevent NULL accesses, and cause the application to crash, but it's
by no means guaranteed.

My worry is that you'll potentially get very weird crashes in systems where
`nullptr` isn't a location that is prevented from executing. I've
accidentally hit this with kernel mode drivers, where something has
actually mapped address zero as a valid address - and then you scratch your
head A LOT for the case where it is executing at address 0x43, and trying
to access some random location you can't use (or invalid instruction, or
whatever it may be).

The only worse bug to understand was when I accidentally overwrote the
entire code up to the point where the memset was looping at - but after the
second or third time I managed to forget to include the string.h [which in
that environment reversed the order of the address and size, so I'd fill
from size, address number of bytes - size typically being small, and
address much larger -> filling all over the place], I learned to recognise
the pattern.

Both cases cause "What the heck is going on here" type situations - even
with good debug tools like in circuit emulators or external debgugers, it's
even worse if you only have regular debugger (or only "printf", "blink the
LED" etc)

Certainly in a debug build, I'd add an assert for `fn != nullptr` in the
`Go` function. Possibly even actively prevent it from getting through in
release builds - presumably the `SomeFunction` is more than a few
instructions anyway.

--
Mats

On 14 June 2016 at 05:07, Gor Nishanov via llvm-dev <llvm-dev at lists.llvm.org
> wrote:

> Hi all:
>
> This question is related to a state machine generated by LLVM for a
> coroutine.
> I stripped all coroutine related details to get to the essence of the
> question.
>
> Let's say I have a state machine that looks like this:
>
>   struct State {
>     FnPtr Fn;
>     State() : Fn(&SomeFunction) {}
>
>     void Go() { (*Fn)(); }
>     void Stop() { Fn = nullptr; }
>     bool IsDone() { return Fn == nullptr; }
>   };
>
> Fn field serves two purposes:
>
> * Cheap check for done. What can be better than compare with zero!
> * Guard against programmer mistake: accidentally calling Go() when in a
>   Stopped state.
>
> Is it an appropriate use of undefined behavior?
>
> Thank you,
> Gor
>
> P.S.
>
> This iassumes -O3 with no ubsan. Sanitizer can, of course, add a null
> check in Go() prior to an indirect call.
> _______________________________________________
> LLVM Developers mailing list
> llvm-dev at lists.llvm.org
> http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-dev
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20160614/6e697c24/attachment.html>


More information about the llvm-dev mailing list