Hi I ran into this problem when optimization was enabled. Without it the code runs fine.
As I'm not x86 assembly fluent that report part is AI generated, but I hope it should be clear what the issue is:
Pelles C 14.50.0 (pocc 14.50.0, polink 14.50.1), Windows 11 x64. Also seen on 13.00.9.
Target /Tx64-coff. Fails at /Ot, /Ox, /Os, /O1 and /O2; correct without /O.
Repro (repro.c):
#include <stdio.h>
#include <stdint.h>
#include <string.h>
static uint32_t get_le32(const uint8_t *f, size_t n)
{
return (uint32_t)f[n - 4] | ((uint32_t)f[n - 3] << 8) |
((uint32_t)f[n - 2] << 16) | ((uint32_t)f[n - 1] << 24);
}
int main(void)
{
uint8_t buf[64];
size_t n;
int bad = 0;
for (n = 0; n < sizeof buf; n++)
buf[n] = (uint8_t)(n * 7u + 1u);
for (n = 4; n <= sizeof buf; n++) {
uint32_t got = get_le32(buf, n), want;
memcpy(&want, buf + n - 4, 4);
if (got != want) { printf("n=%u: got %08X want %08X\n", (unsigned)n, got, want); bad++; }
}
printf("%s\n", bad ? "FAIL" : "OK");
return bad != 0;
}
Build:
pocc /Tx64-coff /std:C11 /Ze /MT /Ot repro.c
polink /SUBSYSTEM:CONSOLE /MACHINE:X64 repro.obj
Result:
without /O : prints OK
/Ot /Ox /Os /O1 /O2 : "CRT: unhandled exception (main) -- terminating"
Generated code for get_le32 at /Ot (pocc /Tx64-asm):
add rcx,rdx
mov rax,4294967292 ; 0x00000000FFFFFFFC
mov eax,dword [rcx+rax] ; reads f + n + 4 GB - 4 -> access violation
ret
Merging the four byte loads into one dword load is fine. The bug is the displacement:
-4 is materialized as the 32-bit value 0xFFFFFFFC zero-extended to 64 bits, instead of
sign-extended (mov rax,-4, or simply dword [rcx+rdx-4]). It looks like the
"n - 4" offset is computed in 32-bit unsigned arithmetic and then widened when the
index is size_t.
Bug have been since version 11 :(