Issue 185274
Summary [CoroCleanup] crash on unused `llvm.coro.subfn.addr` in noop coroutine elision
Labels new issue
Assignees
Reporter cardigan1008
    Here is a crash case when reviewing https://github.com/llvm/llvm-project/pull/179154:

```llvm
define void @load() {
  %frame = call noundef ptr @llvm.coro.noop()
  %resume = call ptr @llvm.coro.subfn.addr(ptr %frame, i8 0)
  ret void
}

; Function Attrs: nounwind memory(none)
declare ptr @llvm.coro.noop() #1
declare ptr @llvm.coro.subfn.addr(ptr, i8)

attributes #1 = { nounwind memory(none) }
```

Compiler Explorer: https://godbolt.org/z/Gz3WPe6Mo

Crash:

```sh
opt: /root/llvm-project/llvm/include/llvm/Support/Casting.h:109: static bool llvm::isa_impl_cl<To, const From*>::doit(const From*) [with To = llvm::Instruction; From = llvm::User]: Assertion `Val && "isa<> used on a null pointer"' failed.
```

Backtrace:

```sh
Stack dump:
0.	Program arguments: /opt/compiler-explorer/clang-assertions-trunk/bin/opt -o /app/output.s -S -passes=coro-cleanup <source>
1.	Running pass "coro-cleanup" on module "<source>"
 #0 0x0000000005c079b8 llvm::sys::PrintStackTrace(llvm::raw_ostream&, int) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x5c079b8)
 #1 0x0000000005c047e4 SignalHandler(int, siginfo_t*, void*) Signals.cpp:0:0
 #2 0x0000730f86e42520 (/lib/x86_64-linux-gnu/libc.so.6+0x42520)
 #3 0x0000730f86e969fc pthread_kill (/lib/x86_64-linux-gnu/libc.so.6+0x969fc)
 #4 0x0000730f86e42476 gsignal (/lib/x86_64-linux-gnu/libc.so.6+0x42476)
 #5 0x0000730f86e287f3 abort (/lib/x86_64-linux-gnu/libc.so.6+0x287f3)
 #6 0x0000730f86e2871b (/lib/x86_64-linux-gnu/libc.so.6+0x2871b)
 #7 0x0000730f86e39e96 (/lib/x86_64-linux-gnu/libc.so.6+0x39e96)
 #8 0x00000000032223c1 (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x32223c1)
 #9 0x000000000322413d (anonymous namespace)::Lowerer::lower(llvm::Function&) CoroCleanup.cpp:0:0
#10 0x000000000322508e llvm::CoroCleanupPass::run(llvm::Module&, llvm::AnalysisManager<llvm::Module>&) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x322508e)
#11 0x00000000031259de llvm::detail::PassModel<llvm::Module, llvm::CoroCleanupPass, llvm::AnalysisManager<llvm::Module>>::run(llvm::Module&, llvm::AnalysisManager<llvm::Module>&) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x31259de)
#12 0x000000000596f831 llvm::PassManager<llvm::Module, llvm::AnalysisManager<llvm::Module>>::run(llvm::Module&, llvm::AnalysisManager<llvm::Module>&) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x596f831)
#13 0x0000000000978e3a llvm::runPassPipeline(llvm::StringRef, llvm::Module&, llvm::TargetMachine*, llvm::TargetLibraryInfoImpl*, llvm::ToolOutputFile*, llvm::ToolOutputFile*, llvm::ToolOutputFile*, llvm::StringRef, llvm::ArrayRef<llvm::PassPlugin>, llvm::ArrayRef<std::function<void (llvm::PassBuilder&)>>, llvm::opt_tool::OutputKind, llvm::opt_tool::VerifierKind, bool, bool, bool, bool, bool, bool, bool, bool) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x978e3a)
#14 0x000000000096ced5 optMain (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x96ced5)
#15 0x0000730f86e29d90 (/lib/x86_64-linux-gnu/libc.so.6+0x29d90)
#16 0x0000730f86e29e40 __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x29e40)
#17 0x0000000000963bb5 _start (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x963bb5)
Program terminated with signal: SIGSEGV
```

> Note: This is a review assisted with a self-built agent. The reproducer was validated manually. Please let me know if anything is wrong.

**Bug Triggering Analysis:**
The provided test case triggers the bug because it contains a `coro.subfn.addr` intrinsic call that has no users. When the `CoroCleanup` pass runs, `NoopCoroElider::visitIntrinsicInst` is called for the `coro.subfn.addr` instruction. It calls `SubFn->getUniqueUndroppableUser()`, which returns `nullptr` because there are 0 users. The code then attempts to cast this `nullptr` to an `Instruction*` using `cast<Instruction>(User)`. The `cast` function in LLVM asserts that the pointer is not null, leading to an assertion failure and a compiler crash.

**Fix Weakness Analysis:**
The weakness in the fix is the assumption that `coro.subfn.addr` will always have exactly one undroppable user (which is expected to be a call or invoke instruction). The fix fails to handle cases where the intrinsic has 0 users (e.g., if the result is unused) or multiple users. By not checking if `User` is null before casting it to an `Instruction`, the compiler is vulnerable to a null pointer dereference or assertion failure. The test case reveals this weakness by explicitly providing a `coro.subfn.addr` instruction with no users.

cc @NewSigma 
_______________________________________________
llvm-bugs mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-bugs

Reply via email to