No equivalent of -fno-delete-null-pointer-checks
#1052
Labels
• toolchain
Related to `rustc`, `bindgen`, `rustdoc`, LLVM, Clippy...
-fno-delete-null-pointer-checks
#1052
Suppose I add this (buggy) code to
rust_minimal.rs
:When I build it,
questionable
is compiled into an unconditional call toprint_not_null
. The compiler assumes thatp
can't be null at the point it's checked, because if it were null, the program would have already executed undefined behavior when it dereferenced it.C compilers perform the same kind of optimization by default, but Linux disables it with the compiler flag
-fno-delete-null-pointer-checks
. rustc has no equivalent option. Implementation-wise, I believe it would be straightforward to add one at least for rustc's LLVM backend, since rustc can do the same thing Clang does when passed-fno-delete-null-pointer-checks
– namely, add the LLVM IR attributenull_pointer_is_valid
to all generated code. Perhaps such an option should be added to the wishlist.On the other hand, null pointer optimizations might not be the end of the world. They only affect code that executes undefined behavior, which is easier to avoid in Rust than in C.
Also, null dereferences usually trap in practice; it doesn't matter if a later null check is eliminated if the kernel can't ever reach that point. For a null dereference not to trap, not only does
mmap_min_addr
have to be 0, the CPU also has to allow kernel accesses to reach userland mappings. On x86 this is prevented by the decade-old SMAP extension, and on arm64 by the PAN extension.However, compiler optimizations can defeat that reasoning. In the above example, once the null check is eliminated,
val
becomes unused, so the load from null is also eliminated. Thus no trap occurs at runtime; you just silently get 'incorrect' behavior (i.e.print_not_null
is called even if the pointer is null). Admittedly, I designed the example specifically to achieve that effect, and real code is pretty unlikely to follow the same pattern. In more realistic cases such as loads that are completely unused, LLVM usually doesn't take advantage of the undefined behavior. So the current threat may not be that high. But that's really just a limitation of LLVM's optimizer, and you never know if it might get smarter in the future.The text was updated successfully, but these errors were encountered: