Visual Studio Access violation Bug in release x64 with default optimization

0

I get the following error:
"Exception thrown at 0x00007FF7998111B4 in BugTest.exe: 0xC0000005: Access violation writing location 0x000000F6C37B3198."
only for x64 release version

I think this is due to default optimization. There is no error when turning off default optimization.
The visual studio version is: VS 14.0.25431.01 Update 3

I create the project this way:

File -> New -> Project ->
Visual C++ -> Win32 -> Win32 Console Application ->
Application Settings -> [CHECK] Empty project -> Finish
Solution Explorer -> Source Files -> Add -> Existing Item ...

This is a silly, pointless example of a much larger project.
It has been cleared as much as possible so that an error can occur.

#define _CRT_SECURE_NO_WARNINGS
#include <windows.h>
#include <stdio.h>

typedef enum {
    CAR_BMW     = 10, CAR_KIA, CAR_LEXUS, CAR_ISUZU,
    CAR_CITROEN = 50, CAR_MAZDA, CAR_FERRARI, CAR_JEEP, CAR_NISSAN,
    CAR_AUDI    = 90, CAR_DACIA, CAR_HYUNDAI, CAR_OPEL
} cars_codes;

typedef struct {
    char brand[64];
    int car_code;
} sCAR;

#define MAX_CARS_PER_GROUP        16
static sCAR* cars[ MAX_CARS_PER_GROUP ];
static unsigned int cars_count = 0;

static const sCAR  car_group[] = {
    { "ISUZU"            , CAR_ISUZU },
    { "LEXUS"            , CAR_LEXUS },
    { "BMW"              , CAR_BMW },
    { "KIA"              , CAR_KIA },
    { "DACIA"            , CAR_DACIA },
    { "AUDI"             , CAR_AUDI },
    { "HYUNDAI"          , CAR_HYUNDAI },
    { "OPEL"             , CAR_OPEL },
    { "CITROEN"          , CAR_CITROEN },
    { "MAZDA"            , CAR_MAZDA },
    { "FERRARI"          , CAR_FERRARI },
    { "JEEP"             , CAR_JEEP },
    { "NISSAN"           , CAR_NISSAN },
    { "", 0 }
};

int get_car_name( int car_code, char *brand ) {
    int rv = 0;
    printf( "%s( %d, 0x%p )", __FUNCTION__, car_code, brand );
    for( unsigned int i = 0; i < cars_count; i++ ) {
        if( cars[i]->car_code == car_code ) {
            strcpy(brand, cars[i]->brand);
            rv = 1;
            break;
        }
    }
    printf( " returns %d\n", rv );
    return rv;
}

void main( void ) {
    int current_cars[ ] =  { CAR_DACIA, CAR_OPEL, CAR_CITROEN, CAR_MAZDA, CAR_JEEP, CAR_NISSAN };
    char b_name[ 32 ];
    unsigned int i;

    for( i = 0; i < MAX_CARS_PER_GROUP; i++ ) {
        if( !car_group[ i ].car_code ) break;
        cars[ i ] = new sCAR( );
        strcpy( cars[ i ]->brand, car_group[ i ].brand );
        cars[ i ]->car_code = car_group[ i ].car_code;
    }
    cars_count = i;

    for( i = 0; i < _countof( current_cars ); i++ ) {
        printf( "i = %d\n", i );
        if( get_car_name( current_cars[ i ], b_name ) ) {
            printf( "%s\n\n", b_name );
        }
    }

    for( i = 0; i < cars_count; delete cars[ i++ ] );
}

The program prints the following and dies:
i = 0
get_car_name( 91, 0x000000F6C37AF8B8 )

I think optimization is miscalculating the address because the wrong address is:
0x000000F6C37B3198

It is calculated like this (I also give the assembly code):

            if( get_car_name( current_cars[ i ], b_name ) ) {
00007FF79981115E  mov         ebx,dword ptr [r14]               // r14 = 0x000000f6c37af8a0
00007FF799811161  lea         r9,[b_name]                   // b_name = 0x000000f6c37af8b8 ""
00007FF799811166  mov         r8d,ebx  
00007FF799811169  lea         rdx,[string "get_car_name" (07FF7998132C8h)]  
00007FF799811170  lea         rcx,[string "%s( %d, 0x%p )" (07FF7998132D8h)]  
00007FF799811177  mov         edi,esi  
00007FF799811179  call        printf (07FF799811010h)  
00007FF79981117E  mov         r8d,dword ptr [cars_count (07FF7998156C0h)]  
00007FF799811185  mov         edx,esi  
00007FF799811187  test        r8d,r8d  
00007FF79981118A  je          main+154h (07FF7998111C4h)  
00007FF79981118C  mov         rcx,r15  
00007FF79981118F  nop  
00007FF799811190  mov         rax,qword ptr [rcx]  
00007FF799811193  cmp         dword ptr [rax+40h],ebx  
00007FF799811196  je          main+135h (07FF7998111A5h)  
00007FF799811198  inc         edx  
00007FF79981119A  add         rcx,8  
00007FF79981119E  cmp         edx,r8d  
00007FF7998111A1  jb          main+120h (07FF799811190h)  
00007FF7998111A3  jmp         main+154h (07FF7998111C4h)  
00007FF7998111A5  lea         rdx,[b_name]  
00007FF7998111AA  sub         rdx,qword ptr [cars (07FF7998156D0h)]  
00007FF7998111B1  movzx       ecx,byte ptr [rax]
// --- Access violation writing location 0x000000F6C37B3198:
00007FF7998111B4  mov         byte ptr [rdx+rax],cl // rdx = 0xfffffe4a99a95cc8, rax = 0x000002ac29d1d4d0, cl ='D'
// -----------------------------------------------------
00007FF7998111B7  lea         rax,[rax+1]  
00007FF7998111BB  test        cl,cl  
00007FF7998111BD  jne         main+141h (07FF7998111B1h)  
00007FF7998111BF  mov         edi,1  
00007FF7998111C4  mov         edx,edi  
00007FF7998111C6  lea         rcx,[string " returns %d\n" (07FF7998132E8h)]  
00007FF7998111CD  call        printf (07FF799811010h)  
00007FF7998111D2  test        edi,edi  
00007FF7998111D4  je          main+177h (07FF7998111E7h)  
            printf( "%s\n\n", b_name );

My problem is that I cannot prevent this error. The bad thing is that when I use printf to clarify situation better, the error disappears!

Later I checked another version of the visual studio:
There are no errors in Visual Studio 2008 Version 9.0.21022.8 RTM version!
It generates a completely different assembly code.

visual-studio
visual-c++
visual-studio-2015
access-violation
asked on Stack Overflow Feb 6, 2020 by Ted • edited Feb 6, 2020 by Ted

0 Answers

Nobody has answered this question yet.


User contributions licensed under CC BY-SA 3.0