T20137 might be depending on C undefined behavior on 32-bit platforms
Consider the following C file reduced from test case T20137
:
#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>
void foo(void *p) {
printf("%" PRIx64 "\n", (uint64_t) p);
}
int main(void) {
foo(0x88888888);
}
On wasm32
, it outputs 88888888
, which looks like a sensible answer: the 32-bit unsigned pointer p
is casted to a 64-bit unsigned integer, therefore it should be a zero-extension. And it's the same result on i386 if compiled by clang
. However, on i386, if compiled by gcc
, the runtime result is ...ffffffff88888888
!
It's obvious that gcc emits assembly that performs a signed extension when casting void*
to uint64_t
. Consider:
unsigned long long foo(void *p) { return p; }
gcc emits:
foo:
mov eax, DWORD PTR [esp+4]
cdq
ret
clang emits:
foo: # @foo
mov eax, dword ptr [esp + 4]
xor edx, edx
ret
Is it a bug in gcc? Or are we encountering some form of C undefined behavior here? I'm leaning towards the latter. Anyway, the 32-bit version of expected stdout of T20137
is dependent on the ill-defined behavior of sign-extending void*
to uint64_t
. Unless there are objections, I'll correct the expected stdout and mark this test as fragile on i386.