Miscompiled address of stack variable in function marked preserve_all when -fno-omit-frame-pointer -mavx
- Dominant language
- LLVM
- Stars
- 40.5k
- Forks
- 18.7k
- PR merge metrics
- PR metrics pending
Description
repro (`clang++ -O2 -std=c++23 -fno-omit-frame-pointer -mavx` on an x86-64 machine):
```c++
// slow() is [[clang::preserve_all]]. With AVX enabled that convention makes it save ymm0-ymm15,
// so its frame is realigned to 32 bytes (`and rsp, -32`) and its locals are addressed relative
// to RSP. It then calls combine(), whose trailing arguments are passed on the stack. The backend
// X86CallFrameOptimization pass turns those argument stores into `push`es (adjusting RSP by 8
// first for alignment), but a `lea` computing the address of the local `suffix` *inside* that
// push window is not rebased for the RSP adjustment. combine() therefore receives `&suffix - 8`
// and reads the neighbouring 8 bytes as suffix._M_len -> a garbage length (a pointer value).
//
// The bug disappears if ANY ONE of these is changed:
// * remove -mavx (no ymm saves -> no 32-byte realignment -> RBP-relative frame)
// * remove -fno-omit-frame-pointer
// * remove [[clang::preserve_all]]
// * add -mllvm -no-x86-call-frame-opt (disables the buggy pass)
#include
#include
#include
#include
[[gnu::noinline]] std::string combine(std::string_view n1, std::string_view n2, const std::string& a, long f1, long f2, const std::string& suffix) {
if (suffix.size() != 22) {
std::printf("MISCOMPILED: suffix.size()=%zu suffix.data()=%p\n", suffix.size(), (const void*)suffix.data());
std::exit(1);
}
return std::string(n1) + std::string(n2) + a + std::to_string(f1) + std::to_string(f2) + suffix;
}
std::string g_a; // a global just so the compiler can't constant-fold `a` away
[[clang::preserve_all]] [[gnu::noinline]] std::string slow() {
std::string suffix("payload-2026-07-17-abc"); // 22 chars; correct size is 22
// `suffix` is a local in slow()'s (32-byte-realigned, RSP-addressed) frame; its address is
// one of the stack arguments, and that is the `lea` the backend fails to rebase.
return combine("n1", "n2", g_a, 111L, 222L, suffix);
}
int main() {
g_a = "some-value-here";
std::string r = slow();
std::printf("OK %s\n", r.c_str());
}
```
[godbolt](https://preserve_all.godbolt.org/z/hsa9zGrWb)
seems to reproduce since clang 17
Contributor guide
Assessment
This issue has not been assessed yet.