Compiling the following code:
double getDouble()
{
double value = 2147483649.0;
return value;
}
int main()
{
Following @AnttiHaapala's answer, I tested the code using optimization /Ox
and found that this will remove the bug as __ftol2_sse
is no longer used:
//; 17 : printf("Direct cast value: %u\n", (unsigned int)getDouble());
push -2147483647 //; 80000001H
push OFFSET $SG10116
call _printf
//; 18 : double d = getDouble();
//; 19 : printf("Indirect cast value: %u\n", (unsigned int)d);
push -2147483647 //; 80000001H
push OFFSET $SG10117
call _printf
add esp, 28 //; 0000001cH
The optimizations inlined getdouble()
and added constant expression evaluation thus removing the need for a conversion at runtime making the bug go away.
Just out of curiosity, I made some more tests, namely changing the code to force float-to-int conversion at runtime. In this case the result is still correct, the compiler, with optimization, uses __dtoui3
in both conversions:
//; 19 : printf("Direct cast value: %u\n", (unsigned int)getDouble(d));
movsd xmm0, QWORD PTR _d$[esp+24]
add esp, 12 //; 0000000cH
call __dtoui3
push eax
push OFFSET $SG9261
call _printf
//; 20 : double db = getDouble(d);
//; 21 : printf("Indirect cast value: %u\n", (unsigned int)db);
movsd xmm0, QWORD PTR _d$[esp+20]
add esp, 8
call __dtoui3
push eax
push OFFSET $SG9262
call _printf
However, preventing inlining, __declspec(noinline) double getDouble(){...}
will bring the bug back:
//; 17 : printf("Direct cast value: %u\n", (unsigned int)getDouble(d));
movsd xmm0, QWORD PTR _d$[esp+76]
add esp, 4
movsd QWORD PTR [esp], xmm0
call _getDouble
call __ftol2_sse
push eax
push OFFSET $SG9261
call _printf
//; 18 : double db = getDouble(d);
movsd xmm0, QWORD PTR _d$[esp+80]
add esp, 8
movsd QWORD PTR [esp], xmm0
call _getDouble
//; 19 : printf("Indirect cast value: %u\n", (unsigned int)db);
call __ftol2_sse
push eax
push OFFSET $SG9262
call _printf
__ftol2_sse
is called in both conversions making the output 2147483648
in both situations, @zwol suspicions were correct.
Compilation details:
cl /permissive- /GS /analyze- /W3 /Gm- /Ox /sdl /D "WIN32" program.c
In Visual Studio:
Disabling RTC
in Project ->
Properties ->
Code Generation and setting Basic Runtime Checks to default.
Enabling optimization in Project ->
Properties ->
Optimization and setting Optimization to /Ox.
With debugger in x86
mode.