3 ms·
> It seems reasonable for the compiler (or some other tool) to produce a hard error here and prevent this code from compiling, saying, hey, this is clearly doin
by comex 8y ago
> It seems reasonable for the compiler (or some other tool) to produce a hard error here and prevent this code from compiling, saying, hey, this is clearly doing something unwanted.
The thing is, the redundant null check usually doesn’t appear literally in the source, but comes from an inlined function call (or even a macro). In that case, the null check is probably not a mistake; it’s just that this particular caller of the function that got inlined never passes null, and so will never trigger that code path.
I do think there’s unexplored potential for compilers to identify when they’ve eliminated code that didn’t come from inlining, and warn the user about the potential bug. However, this is much easier said than done, since the IR has gone through a lot of transformations by that point and there are a lot of edge cases to worry about. For example, even if all the IR instructions corresponding to a given piece of source code are dead, that code might still have affected the function compilation in some manner and thus isn’t useless – such as by being merged with a different (or perhaps redundant) computation, or by affecting control flow.
Also, even if some code path really is useless as compiled, it might be for innocuous reasons. For example, perhaps a given null check was not itself inlined, but the value being checked comes from an inlined function:
void *get_a_pointer(void) {
static int x;
return &x; // not null!
}
int main(void) {
void *p = get_a_pointer();
if (p == NULL) …
}
Unlike in the reverse situation where an inlined null check might be useful to another caller, here we know that that null check will never fire – that is, in this program, in this configuration, the check is useless. But perhaps with a different set of configuration flags, or on a different platform, the code uses a different implementation of get_a_pointer() which could return null. Or perhaps there is an abstraction boundary between main and get_a_pointer, where the documented interface of get_a_pointer says it might return null: even if the current implementation never does, the author expects that that might change in a future version of the code, so clients should proactively include a null check to avoid future breakage. (Of course, get_a_pointer might be part of a third-party library, and the author of main might have never even peeped at its implementation. These situations are especially common if you’re using LTO.)