<table border="1" cellspacing="0" cellpadding="8">
    <tr>
        <th>Issue</th>
        <td>
            <a href=https://github.com/llvm/llvm-project/issues/141361>141361</a>
        </td>
    </tr>

    <tr>
        <th>Summary</th>
        <td>
            `va_arg` miscompiles on `x86_64`
        </td>
    </tr>

    <tr>
      <th>Labels</th>
      <td>
            new issue
      </td>
    </tr>

    <tr>
      <th>Assignees</th>
      <td>
      </td>
    </tr>

    <tr>
      <th>Reporter</th>
      <td>
          folkertdev
      </td>
    </tr>
</table>

<pre>
    The `good` function below works as expected, but the `bad` function miscompiles, and will read uninitialized memory.

https://godbolt.org/z/PWsMaYerv

```llvm
; Function Attrs: nounwind nonlazybind uwtable
define i64 @"bad"(ptr align 8 %0) unnamed_addr #3 {
start:
  %1 = alloca ptr, align 8
  store ptr %0, ptr %1, align 8
  %2 = load ptr, ptr %1, align 8
  %3 = va_arg ptr %2, i64
 ret i64 %3
}

; Function Attrs: nounwind nonlazybind uwtable
define i64 @"good"(ptr align 8 %0) unnamed_addr #3 {
start:
  %3 = va_arg ptr %0, i64
  ret i64 %3
}
```

I don't see why storing and then loading a pointer, then using it, would cause the `va_arg` to be invalid.

---

<details open>
<summary>build/run instructions</summary>
<br>


```c
#include <stdarg.h>
#include <assert.h>
#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>

extern size_t good(va_list ap);
extern size_t bad(va_list ap);

int tester(size_t (*fn)(va_list), ...) {
    size_t ret = 0;
 va_list ap;
    va_start(ap, fn);
    ret = fn(ap);
    va_end(ap);
 return ret;
}

int main(int argc, char* argv[]) {
    // assert(tester(good, 0x01LL, 0x02, 0x03LL) == 1);
    assert(tester(bad, 0x01LL, 0x02, 0x03LL) == 1);

    return 0;
}
```

Run this as

```
> clang --version
ClangBuiltLinux clang version 20.1.5 (https://github.com/llvm/llvm-project.git 7b09d7b446383b71b63d429b21ee45ba389c5134)
Target: x86_64-unknown-linux-gnu
Thread model: posix
InstalledDir: ...
> clang bug.c bug.ll -o bug
> ./bug
> valgrind --track-origins=yes ./bug
```

</details>

the run will segfault, valgrind shows

```
==378134== Use of uninitialised value of size 8
==378134== at 0x1092BE: bad (in /tmp/bug)
==378134==    by 0x1091D1: tester (in /tmp/bug)
==378134==    by 0x109265: main (in /tmp/bug)
==378134== Uninitialised value was created by a stack allocation
==378134==    at 0x1092A0: bad (in /tmp/bug)
==378134== 
==378134== Invalid read of size 8
==378134==    at 0x1092BE: bad (in /tmp/bug)
==378134==    by 0x1091D1: tester (in /tmp/bug)
==378134==    by 0x109265: main (in /tmp/bug)
==378134==  Address 0x100000000000011 is not stack'd, malloc'd or (recently) free'd
==378134== 
==378134== 
==378134== Process terminating with default action of signal 11 (SIGSEGV)
==378134==  General Protection Fault
==378134==    at 0x1092BE: bad (in /tmp/bug)
==378134==    by 0x1091D1: tester (in /tmp/bug)
==378134==    by 0x109265: main (in /tmp/bug)
```

>From what I can tell, the offending code is 

```asm
mov rcx, qword ptr [rsp - 32]
mov     edx, dword ptr [rsp - 12]
mov rsi, qword ptr [rcx + 16]
```

Nothing useful is stored at `rsp - 32`, it is uninitialized memory! 

---

Probably this mostly went unnoticed because clang uses its own implementation of `va_arg`, and seemingly never uses this LLVM intrinsic. 

This issue came up in the context of https://github.com/rust-lang/rust/issues/44930#issuecomment-2902519131, where we're trying to improve the API for C variadic functions in rust. Apparently so far the optimizer/inliner have made sure invalid patterns did not occur, but that is unreliable.

this is an issue that seems similar, but has less information https://github.com/llvm/llvm-project/issues/61021.

</pre>
<img width="1" height="1" alt="" src="http://email.email.llvm.org/o/eJzcWEuPG7kR_jXUpSCBzW69DjpoZqyFAW9gZL0b5DRgN0stxmxSIdl6-NcHRbZkaSxvYCeXRBiMyOLHYr1YVZQMQbcWccWmT2z6MpJ93Dm_2jrzGX1UeBjVTp1Xn3YIbMZb5xSbcdj2tonaWajRuCMcnf8cQAbA0x6biIqJZ6j7CDFvq-X9rk6HxnV7bTAQUloFR20MeJQKequtjloa_QUVdNg5f54wvmZ8vYtxH1i5ZmLDxKZ1qnYmTpxvmdh8YWLz8W_hV_l39IcMZzOe_4w5dDQvn2BzkWEdoydeYF1vj9oqsM4a-eVc07g_RlkbZHytcKstgp5VwCrOhCBlhGBisY8epNGthQUwMeVMLKG3VnaoXqVSHpgoS2DzJ8bXIUofSXK-BgIXwMoXkMa4RsI--mSGzCtBQnQeaWHg_HwZF2-RTExFYmacVBdWfwIuE_ggX6VvLzhBOD2rCOMxZmXFtCSbzV8GY_5XjJcC6D-23iMd-I0O31HiEg5ZofegnGViHiEgwnF3TkbXtk3xGHdok0kTAfZO24jJtmmlD0TXkQhH1xsFjewDXgI-i0YxHx3UCNoepNFqCOPxeHyx6bPCKLUJ4PZoWfkuE0PfddKfWfmu7rVRTGx8b0HbEH2fHBBY-czE5isu76v9MLwP_4YmotS2Mb1CoAOikr6d7Ab43ZoMAX18vBai0vb7a0bX39_nrkt8jaeI3kLQX_A1Qg6KxUG-Gh0iyD0TS1Y-fYNLN-8RjPG1thEihuSjxYBnYsHEemsJd92XJs8wmUwo4nJ8AcDlDIocCi6eOcPNaeUFepCvOSLFgoR4hnzEdf3Cg8iLGzGHvWjVG7rH2HtLX4M-l0tHWnVSEx8aSt82dF6zk56JNc0POW_f65LzI2RPMrG4GiZb-hn4iRcfPgwjMXyXRFmS5CR8cSf2t6ySM36Q01f7kLr8Ttn7y_nX3kLcaSoqb4I5Rfo7aIy0LYzHB_RBO8v4-pkoT7028YO2_WlADOsg-KSYTCkk3hQRHXd9PWlcx8Qm1Yn8Nd579w9s4qTVEeY1X6p5XVWzclHW86KelaoSy1oUiNW0luVi2UyLsiJF-fqT9C15cg2nxex1Vo17-9m6ox0bkmvc2p5Au1TsOqfQEHTvgj5RVrIhSmNQvWhPdIrTW43rvp006b8xMHY0GtYnTGy-zg7StJ6S8XgcvWw-j53XrabE8XLGcAu-N3xOLENWut5XSmuUglKVDthuZW9S7rseE3bu-NBVFALlfEHWyeHwe0Bw25syH1ARnz6R6RqmYvVgp4zATwVfiqd3ZJpaKkgXg-I9dvtBpeSDB7sBoD5nBsVLQQxyLP8kDzGbEg-6nT_C4fcHah9lgMajjKiIvYQQZfN56A5iju7HwlwtsuY_YZHH1Pe5VuVm7N945FaE_2GnwFopjyEkJjefogAdwLqYPcLEPOW8LnmGZuCSpB4btNGcKeltPWIC_oDJH1M_eteQUBF9p62M1HEcddyBwnT_QOZmLPmotdJAUZA0v73_5bd3v_zxfW1_QYteGjogYuaxSRf6_8fH90lt410Hx52M8B4aaSGiMUMrB267RZu6vMYpJH-_yWIy0NuhcwfwzYl2_fPovMpt5_TJhz2MoRRUgzOKPqgSUn2LLG6QPuhv-TUnYOIJilnGvdHkLy7uSNY-4LY3JG16KShyEZvxqzSz3A5HQjx6UDFRwJtm9KN3tazNOdfdzoVoznBEG6ktd1E3lJ0wt7m5FvUBA-gYwB0t6G5vsEMb5SUob_vgyzMvIHbatuYMFg_oM4t04IcPf_wK2kavbdDNZJDuEy3pEHqERnYI_R60TX5rnI14inTQn1R034c4JmGHMRObxC0wsamqZcmpTyVC4zoSfiyWXEyLZVGmt9Nxhx7hSBfaI0R_JttHR8p6d8jt_vrje9g6D1QMvZZKN9eHbiBh6dgJrPd76VOSgOBgK30Ovn3Unf5CDdVGW6MtetjJA0InFULo_fXpAHsZqRcOoLRKKck1Te-_PrTl4GuPRtPra3Kp3MmAIO1gxoQkNwQIutNGXnnsZABDCUfbrfNd9uOPdUu35p0VXBQkxUitSrUsl3KEq2JeLQo-41U12q2qpSwW82JW1Nt5vdw25bKui2bKy6bmqOr5SK8EF1M-FVUx57yqJnxWSi7LLedlvVgWBas4dlKbCQkxcb4dpeNXRVWUs2JkZI0mpJ82hLB4zCag9-f0ZeRXSfK6bwOrODX54SubqKPB1d1L7uZHC3CWoju3d2zGR703q5-31CDtYSX-FQAA___aOi-N">