Skip on msan instrumented functions since this hurts msan's usefulness.
Add a flag to disable while ToT LLVM users fix regressions (the flag may be useful for bisecting files). This flag will be removed in the future.
Differential D133036
[InstCombine] Treat passing undef to noundef params as UB aeubanks on Aug 31 2022, 11:26 AM. Authored by
Details Skip on msan instrumented functions since this hurts msan's usefulness. Add a flag to disable while ToT LLVM users fix regressions (the flag may be useful for bisecting files). This flag will be removed in the future.
Diff Detail
Unit Tests Event Timeline
Comment Actions FYI, this change broke Wine (at least on arm and aarch64). Not saying that it is legit breakage of code that actually was UB to begin with though - it's going to take some time to figure out what's broken though. Comment Actions This change has broken LLDB Arm/AArch64 Linux buildbots. I dont really understand Comment Actions Apparently some problem occuring due to trouble with ASAN exception Comment Actions This also broke Rust when compiled at LLVM head: https://buildkite.com/llvm-project/rust-llvm-integrate-prototype/builds/13166#0182fb4a-0f2d-4f2e-830f-f62b463b8d48. (I don't know whether this was some existing UB that got only exposed by this patch or not, but wanted to make you aware. Reproduces with 2+ codegen units and a 1+ optimization level). Comment Actions This change also broken emscripten in some odd ways: https://app.circleci.com/pipelines/github/emscripten-core/emscripten/23359/workflows/4080be5f-bd82-45b9-a355-3a5d4f4ef977/jobs/564543. The revert seems to have fixed it. Comment Actions "fix" lldb test (hopefully) Comment Actions add flag to disable (to be removed in the future) Comment Actions I'd like to block this on -fsanitize-memory-param-retval (aka msan eager checks) being enabled by default. It seems pretty clear that there is a *lot* of UB due to uninitialized parameters floating around, so we should at least make sure that it is detected in default sanitizer configurations before we start exploiting it this aggressively. Comment Actions The default switch has happened, so unblocking this.
Comment Actions I'm still trying to properly minimize this, but this definitely interacts badly with other optimizations (which triggers the Rust CI failure I mentioned above):
I don't know which component should be considered "at fault" here (or if the readnone bit is even relevant). Comment Actions @TimNN Do you have an IR sample for this? DAE is supposed to strip UB-implying attributes when converting arguments to poison here: https://github.com/llvm/llvm-project/blob/cbe5b2dd914b7ee47bb4d0f67af154a40be4d208/llvm/lib/Transforms/IPO/DeadArgumentElimination.cpp#LL291C17-L291C37 Comment Actions I've included excerpts from the IR below. It will take me a bit to provide something compilable. Though you are right, the noundef did indeed get removed from the call. *** IR Dump Before DeadArgumentEliminationPass on [module] *** ; Function Attrs: nonlazybind uwtable define void @_RNvXs2_NtNtCs840rfDNPFol_10proc_macro6bridge3rpcbINtB5_6EncodeuE6encodeB9_(i1 noundef zeroext %0, ptr noalias noundef align 8 dereferenceable(40) %1, ptr noalias nocapture noundef nonnull readnone align 1 %2) unnamed_addr #0 !dbg !18135 { %4 = zext i1 %0 to i8, !dbg !18137 call void @_RNvXs0_NtNtCs840rfDNPFol_10proc_macro6bridge3rpchINtB5_6EncodeuE6encodeB9_(i8 %4, ptr noalias noundef nonnull align 8 dereferenceable(40) %1, ptr noalias noundef nonnull align 1 %2), !dbg !18137 ret void, !dbg !18138 } *** IR Dump After DeadArgumentEliminationPass on [module] *** ; Function Attrs: nonlazybind uwtable define void @_RNvXs2_NtNtCs840rfDNPFol_10proc_macro6bridge3rpcbINtB5_6EncodeuE6encodeB9_(i1 noundef zeroext %0, ptr noalias noundef align 8 dereferenceable(40) %1, ptr noalias nocapture noundef nonnull readnone align 1 %2) unnamed_addr #0 !dbg !18136 { %4 = zext i1 %0 to i8, !dbg !18138 call void @_RNvXs0_NtNtCs840rfDNPFol_10proc_macro6bridge3rpchINtB5_6EncodeuE6encodeB9_(i8 %4, ptr noalias noundef nonnull align 8 dereferenceable(40) %1, ptr noalias nonnull align 1 poison), !dbg !18138 ret void, !dbg !18139 } *** IR Dump Before InstCombinePass on _RNvXs2_NtNtCs840rfDNPFol_10proc_macro6bridge3rpcbINtB5_6EncodeuE6encodeB9_ *** ; Function Attrs: nonlazybind uwtable define available_externally void @_RNvXs2_NtNtCs840rfDNPFol_10proc_macro6bridge3rpcbINtB5_6EncodeuE6encodeB9_(i1 noundef zeroext %0, ptr noalias noundef align 8 dereferenceable(40) %1, ptr noalias nocapture noundef nonnull readnone align 1 %2) unnamed_addr #2 !dbg !20759 { %4 = zext i1 %0 to i8, !dbg !20762 call void @_RNvXs0_NtNtCs840rfDNPFol_10proc_macro6bridge3rpchINtB5_6EncodeuE6encodeB9_(i8 %4, ptr noalias noundef nonnull align 8 dereferenceable(40) %1, ptr noalias nonnull align 1 poison), !dbg !20762 ret void, !dbg !20763 } *** IR Dump After InstCombinePass on _RNvXs2_NtNtCs840rfDNPFol_10proc_macro6bridge3rpcbINtB5_6EncodeuE6encodeB9_ *** ; Function Attrs: nonlazybind uwtable define available_externally void @_RNvXs2_NtNtCs840rfDNPFol_10proc_macro6bridge3rpcbINtB5_6EncodeuE6encodeB9_(i1 noundef zeroext %0, ptr noalias noundef align 8 dereferenceable(40) %1, ptr noalias nocapture noundef nonnull readnone align 1 %2) unnamed_addr #2 !dbg !20759 { store i1 true, ptr poison, align 1 ret void, !dbg !20762 } Comment Actions I didn't manage to repro with opt, so still no compilable IR. I did some more debugging, though:
Comment Actions I'm sorry for the noise. Further investigation has shown that this happens when Rust is doing (thin) LTO, and I don't think this patch can be considered in any way "at fault" here, so this is the last you'll hear from me on the topic here. I don't know whether the fault is with how Rust implements (thin) LTO or something on the LLVM side. Basically, after running the FunctionImporter on a module, we end up with a define available_externally void outer and a declare void inner, presumably coming from different modules. outer contains the call to inner with poison, but the parameter is noundef on the declaration on inner. edit: Issue in the Rust repo: https://github.com/rust-lang/rust/issues/104377 edit2: LLVM issue: https://github.com/llvm/llvm-project/issues/58976 Comment Actions The ThinLTO related breakage I mentioned above should be fixed as of https://github.com/llvm/llvm-project/commit/451799bb8261bde52bbfef226d019caf1d82aa42. |
Call.isPassingUndefUB(I). You probably want to flip the checks, because the UndefValue check is cheaper. Also add tests with dereferenceable instead of noundef.