| 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