[llvm-dev] GEP with a null pointer base

Peter Lawrence via llvm-dev llvm-dev at lists.llvm.org
Wed Jul 12 11:17:33 PDT 2017

          Here is the definition accepted by Hal of what we’re doing

> 1. Sometimes there are abstraction penalties in C++ code
> 2. That can be optimized away after template instantiation, function inlining, etc
> 3. When they for example exhibit this pattern
> 	if (A) {
> 		stuff;
> 	} else {
> 		other stuff including “undefined behavior”;
> 	}
> 4. Where the compiler assumes “undefined behavior” doesn’t actually happen because
>    In the C language standard it is the users responsibility to avoid it
> 5. Therefore in this example the compiler can a) delete the else-clause
>     b) delete the if-cond, c) assume A is true and propagate that information

We are actively deleting undefined behavior, and the question is why
given that doing so potentially masks a real source code bug.
At the very least deleting undefined behavior should not be the default.

Peter Lawrence.

> On Jul 12, 2017, at 2:24 AM, David Chisnall <David.Chisnall at cl.cam.ac.uk> wrote:
> On 10 Jul 2017, at 19:36, Peter Lawrence via llvm-dev <llvm-dev at lists.llvm.org> wrote:
>> why should we ever optimize / delete any UB at all ?
> No one has addressed this yet, which may be why you are still under the impression that it’s under discussion.  You seem to have some misconceptions about UB.  There are two major reasons for UB in a language such as C:
> 1. The safe version may be prohibitively expensive on some architectures.  For example, division by zero will give a trap on some architectures or an unspecified value on others.  If the C specification stated that it gave an unspecified value, then on architectures that trap every division would have to be wrapped in a branch that tested if the divisor was zero and branched over the divide instruction if so.  This would lead to very inefficient code on these architectures, so the C standard says that anything is allowed to happen.
> 2. Some properties are effectively impossible to verify statically[1].  For example, it is undefined behaviour in C to use a pointer to a deallocated object[2].  If C required well-defined behaviour here then it would effectively be mandating some form of garbage collector: you’d need to either find all pointers to an object and null them on free, or you’d need to mark the object, check the mark on every load, and not reuse the memory until later.  This would be unacceptable overhead for a C implementation.  A lot of other things are in this category.
> Many things are a mixture of these.  Most optimisations that rely on undefined behaviour are not saying ‘aha, we’ve spotted that the program invokes undefined behaviour, we can replace the whole thing with a trap instruction!’, they’re saying ‘this program does either X or Y, X would be undefined behaviour and so we can assume that it does Y’.  Not being able to do the latter would mean that they’d need to insert run-time checks each time, which would negate the optimisation and *in well-written code would never be hit*.
> The cases where the compiler can statically prove that undefined behaviour is present are comparatively rare.
> David
> [1] Note: Some of these are possible with whole-program analysis, so if you’re happy without shared libraries and with week-long compile times then it’s possible.
> [2] The wording of this actually means that it’s impossible to implement malloc() in ISO C, because as soon as the pointer has been passed to free then it becomes invalid and using it to put the object on a free list invokes undefined behaviour.

More information about the llvm-dev mailing list