-
Notifications
You must be signed in to change notification settings - Fork 12.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Reading uninitialized memory must be poison, not undef #52930
Comments
Generally sounds good, but I believe we also need to auto-upgrade existing bitcode by replacing all loads with freeze(load), which will significantly pessimize the ability to optimize old bitcode. |
Right, forgot that. Added to the todo list, thanks! |
Sounds like a great plan! |
NewGVN patch fixed in f1c18ac |
See also: https://reviews.llvm.org/D89050 (just for documentation so we don't forget) |
Clang frontend must be able to use the !noundef to annotate lvalues that must be initialized. |
Or |
That's a huge can of worms. It's hard to define the semantics of arithmetic operations with bitwise poison semantics. Several people have tried in the past and failed. |
yeah I don't think we've ever seen a proposal along these lines that resulted in rules that were comprehensible in practice to the target audience, people trying to reason about optimizations. my take on what I saw was that it was so complicated that one would simply need to blindly trust alive or whatever other automated checking tool people write |
This removes memset with undef char. We already do this for stores of undef value. This comes with the caveat that this optimization is not, strictly speaking, legal for undef values, because we might be overwriting a poison value. However, our entire load/store model currently still operates on undef values, so we need to support undef here as well for internal consistency. Once #52930 is resolved, these and related folds can be limited to poison -- I've added FIXMEs to that effect. Differential Revision: https://reviews.llvm.org/D124173
Are these previously considered proposals and their issues summarized somewhere?
FWIW https://discourse.llvm.org/t/a-memory-model-for-llvm-ir-supporting-limited-type-punning/61948 proposes bitwise poison where for arithmetic, if any input bit is poison, the full output is poison. |
Currently we consider loads of uninitialized memory to be undef. This is both sub-optimal and a source of miscompilations.
For example, instsimplify & newgvn convert
phi(X, undef) -> X
. This is wrong asX
might be poison. We had the same issue withselect
but it has already been fixed.Fixing this bug is related with uninit memory because sroa/mem2reg create phis with undef. And we need to be able to fold those away.
We have a patch for langref, sroa, mem2reg here: https://reviews.llvm.org/D104648
I have patches locally for InstSimplify & NewGVN to fix the phi issue mentioned above.
Changing the semantics of load of uninit memory breaks compatibility. Although most users won't notice, we would need to interface with the major frontends.
For clang, we would need to fix codegen of bit-fields as at the least the first field store loads uninit memory before masking it. The easy way is to just freeze the loaded value. Spill-over of poison from different fields is not an issue as if one field becomes poison is because some UB already happened in the program so we can spill over poison to neighboring fields.
Bitfields aren't very common, so this shouldn't be a major issue.
On LLVM's side, I believe the only issue is load widening. This must be either be removed at IR level, or we need to use vectors (or the byte type) for the widened type.
In summary, todo:
cc @aqjune @regehr @nikic @rotateright @LebedevRI @alinas
The text was updated successfully, but these errors were encountered: