Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Possible C/C++ compiler bug in Visual Studio 2013

The following C or C++ code should have as output "11,11,11," however using Visual Studio Professional 2013 (Version 12.0.40629.00 Update 5) the output is "11,0,0,"! This only occurs in a release build, and disappears when optimization is turned off. Is this a compiler bug?

#include <stdio.h>

int main(void)
{
    int A[100] = { 0 };
    int row = 0;   // BUG disappears if we make this const or short or char...
    int ncols = 3; // BUG disappears if we make this const or short or char...

    for (int y = row; y <= row; ++y)
    {
        for (int x = 0; x < ncols; ++x)
        {
            const int index = y * ncols + x;

            //A[index] = 11;           // (no bug !)
            *(A + index) = 11;       // BUG!!!
            //*(A + y*ncols+x) = 11;   // (no bug !)
            //*(A + (y*ncols+x)) = 11; // BUG!!!
        }
    }

    for (int x = 0; x < ncols; ++x)
    {
        printf("%d,", A[x]);
    }

    return 0;
}
like image 940
AvD Avatar asked Mar 01 '17 17:03

AvD


1 Answers

Yes, it appears to be a compiler bug. In Win32 version of the code the compiler uses register esi to represent y and register edx to represent x. As @Ajay Brahmakshatriya correctly noted in the comments, it appears that the compiler performed an attempt to exchange the cycles (swap the outer with the inner), but ended up with incorrect code. The very last conditional jump instruction, which is supposed to represent the [exchanged] inner cycle, for some reason transfers control to a location that checks esi as well. That check ends iterations prematurely.

0018206B  xor         esi,esi             ; This is `y`
0018206D  xor         edx,edx             ; This is `x`
...
00182070  test        esi,esi  
00182072  jg          main+5Ch (018209Ch) ; Exit from the outer cycle?

00182074  lea         eax,[edx+esi*2]     ; Recalculate the starting storage location
00182077  add         eax,esi             ; for the next cycle:
00182079  lea         ecx,[A]             ; eax = esi * 3 + edx
0018207F  lea         eax,[ecx+eax*4]     ; eax = &A[eax]
...
00182082  mov         ecx,1               ; It is not exactly clear to me what this is 
00182087  sub         ecx,esi             ; supposed to do, but when `esi` is `0`, it 
00182089  add         esi,ecx             ; leaves `ecx` as 1, which is correct 
                                          ; number of iterations for outer cycle
...
00182090  mov         dword ptr [eax],0Bh ; Storing the value
00182096  lea         eax,[eax+0Ch]       ; Updating the pointer for the next storage location 
00182099  dec         ecx  
0018209A  jne         main+50h (0182090h) ; Outer cycle [exchanged]

0018209C  inc         edx  
0018209D  cmp         edx,3  
001820A0  jl          main+30h (0182070h) ; Inner cycle [exchanged]: for some reason it
                                          ; jumps to `test esi,esi`, which is what
                                          ; suddenly terminates the iterations
like image 101
AnT Avatar answered Oct 15 '22 21:10

AnT