Background:
We just switched our development environment to VC ++ 2015 with VC ++ 2008. Right after that we discovered a problem: the program raised the division by 0, despite the fact that the divider is divided into C ++ code.
Test code:
#include <cstdlib>
int test(int n, int test_for_zero)
{
int result = 0;
for (int i = 0; i < n; ++i) {
if (test_for_zero)
result += rand() >> ((8 % test_for_zero) * test_for_zero);
}
return result;
}
int main()
{
return test(rand(), rand() & 0x80000000);
}
Compiled VC ++ 2015 Update 3 or VC ++ 2017 with default settings, at startup, it increases the division by zero. Compiled VC 2008 works fine.
Analysis:
; 6 : for (int i = 0; i < n; ++i) {
test edi, edi
jle SHORT $LN15@main
; 7 :
; 8 : if (test_for_zero)
; 9 : result += rand() >> ((8 % test_for_zero) * test_for_zero);
mov ecx, DWORD PTR _test_for_zero$1$[ebp]
mov eax, 8
cdq
idiv ecx ; <== IT HERE, IDIV BEFORE CHECKING FOR ZERO
mov eax, edx
imul eax, ecx
mov DWORD PTR tv147[ebp], eax
test ecx, ecx
je SHORT $LN15@main
$LL11@main:
call ebx
mov ecx, DWORD PTR tv147[ebp]
sar eax, cl
add esi, eax
sub edi, 1
jne SHORT $LL11@main
The compiler takes the constant part ((8 % test_for_zero) * test_for_zero)
from the body of the loop and simply forgets to test test_for_zero
before dividing. Obviously, it can be easily fixed in place by simply completing the compiler task, but correctly.
, -d2SSAOptimizer-
-Oxx
, - -Od
.
:
- ? ++ VC 2008, ?
- : - , -Ob?