Prehistory:
We have just switched our developing environment to VC++ 2015 from VC++ 2008. Right after that we have found the issue: program raised division by 0 despite testing divider in 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 by VC++ 2015 Update 3 or VC++ 2017 with default Release options, on run it raises division by zero. Compiled by VC 2008 runs just 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'S 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 constant part ((8 % test_for_zero) * test_for_zero)
out of loop body and just forget for testing test_for_zero
before division. Obviously it can be fixed easily at place just by doing the compiler job but correctly.
I've played with several compiler options, like -d2SSAOptimizer-
and -Oxx
, but the only option to fix this is -Od
.
Questions:
- Is it a bug or not? The C++ standard was heavily changed since VC 2008 so may it be affected like this?
- The main question, is there any workaround to fix the issue thru compiler options, except -Ob?