Issue 208611
Summary [x86] Incorrect load combining causing OOB reads (and thus segfaults at runtime)
Labels new issue
Assignees
Reporter scottmcm
    Context: Rust issue in today's 1.97 release, https://github.com/rust-lang/rust/issues/159035
Rust repro with opt pipeline, https://rust.godbolt.org/z/dTPGY3rY1

Take this LLVM IR, particularly noting that `%0` can be `-1`, `0`, or `1` as conveyed by the `!range` attribute
```llvm
define { i32, i32 } @"example[aafd2ff9cfc6cff8]::run"(ptr dead_on_return noalias nofree noundef readonly align 8 captures(none) dereferenceable(24) %c) unnamed_addr {
start:
  %0 = load i64, ptr %c, align 8, !range !4, !noundef !5
  %.not = icmp ne i64 %0, -1
  %_3.sroa.5.0.c.sroa_idx = getelementptr inbounds nuw i8, ptr %c, i64 12
  %_3.sroa.5.0.copyload = load i32, ptr %_3.sroa.5.0.c.sroa_idx, align 4
  %1 = trunc nuw i64 %0 to i1
  %2 = getelementptr inbounds nuw i8, ptr %c, i64 16
  %_3.sroa.6.0.copyload = load i32, ptr %2, align 8
  %_4.sroa.0.1 = select i1 %1, i32 %_3.sroa.6.0.copyload, i32 %_3.sroa.5.0.copyload
  %_0.sroa.3.0 = select i1 %.not, i32 %_4.sroa.0.1, i32 undef
  %_0.sroa.0.0 = zext i1 %.not to i32
  %3 = insertvalue { i32, i32 } poison, i32 %_0.sroa.0.0, 0
  %4 = insertvalue { i32, i32 } %3, i32 %_0.sroa.3.0, 1
  ret { i32, i32 } %4
}

!4 = !{i64 -1, i64 2}
!5 = !{}
```

Today on llc trunk that compiles to the following: <https://llvm.godbolt.org/z/TcY99vhjE>
```asm
"example[aafd2ff9cfc6cff8]::run":
        mov     rcx, qword ptr [rdi]
        xor     eax, eax
        cmp     rcx, -1
        setne   al
        mov     ecx, ecx
        mov     edx, dword ptr [rdi + 4*rcx + 12]
        ret
```

`rcx` there maps to `%0`, so it can be `-1`, `0`, or `1` (as i64).

If it stayed that way, that would be fine, as the `[rdi + 4*rcx + 12]` would read 4 bytes from `rdi + 8`, `rdi + 12`, or `rdi + 16`, all of which are within the `dereferenceable(24)`.

However, that `mov ecx, ecx` changes `rcx` to instead be `0x00000000FFFFFFFF`, `0`, or `1` (as i64`), and thus the following `mov` reads massively out of bounds, causing a segfault.

---

Apologies in advance if I got the logic chain wrong here somewhere.  I'm reasonably good at middle-end IR but worse at assembly and completely unfamiliar with backend IR.

I think this is x86-specific because it was reported that neither aarch64 nor riscv64gc hit a problem here (Rust Zulip [#t-compiler > Miscompilation in 1.97.0 with new Option::None discriminant @ 💬](https://rust-lang.zulipchat.com/#narrow/channel/131828-t-compiler/topic/Miscompilation.20in.201.2E97.2E0.20with.20new.20Option.3A.3ANone.20discriminant/near/609362902)).
_______________________________________________
llvm-bugs mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-bugs

Reply via email to