Issue 185089
Summary [RISCV] musttail with indirect arguments causes use-after-free
Labels new issue
Assignees
Reporter xroche
    On RV32, `musttail` calls where arguments are passed indirectly (`CCValAssign::Indirect`) produce dangling pointers. The caller loads data from the incoming indirect pointer, creates a **new** stack temporary, stores the data there, and passes a pointer to the new slot. The tail call then deallocates the caller's stack frame before the callee executes, leaving the pointer dangling.

Example: `fp128` on RV32 is passed indirectly (16 bytes, pointer in `a0`). `i128` on RV32 also triggers this path.

```llvm
declare i32 @callee(fp128 %a)

define i32 @caller(fp128 %a) {
entry:
  %v = musttail call i32 @callee(fp128 %a)
  ret i32 %v
}
```

On RV32, the generated code:
1. Loads fp128 data from incoming pointer (caller's caller's frame)
2. Creates a new stack slot via `DAG.CreateStackTemporary`
3. Stores data to the new stack slot
4. Passes pointer to new stack slot in `a0`
5. Tail-jumps to callee -- stack frame is deallocated, pointer is now dangling

The correct behavior for `musttail` is to **forward the original incoming pointer** directly, since `musttail` guarantees matching prototypes. The incoming pointer points to the caller's caller's frame, which remains valid after the tail call.

Note: PR #184972 fixed the non-`musttail` case by rejecting tail calls with indirect args entirely. This issue is specifically about `musttail`, which *must* be a tail call and therefore needs a different fix (forwarding the pointer rather than rejecting the optimization).

On RV64, `fp128` and `i128` fit in 2 registers (direct), so this issue only manifests on RV32 (or with types larger than 2xXLEN on RV64).
_______________________________________________
llvm-bugs mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-bugs

Reply via email to