MSVC compiler bug when adding 0 to a pointer with /arch:AVX2; related to Warning C26451

113 Views Asked by At

I’m having a bug after compiling the below piece of code with /O2, /Ob2, /arch:AVX2 flags. I am using Microsoft Visual Studio Community 2019 Version 16.4.6 on a Win64.

Running the below piece of code results in the following output. Note the middle column in the first and third lines:

(1) NOT OK (Line 0 != Line 2) :
000001B5B43B07D0 000001B5B43BD9D0 000001B5B43BDA10
000001B5B43B07E8 000001B5B43BD9DC 000001B5B43BDA1C
000001B5B43B07D0 000001B5B43BD9DC 000001B5B43BDA1C
000001B5B43B07E8 000001B5B43BD9DC 000001B5B43BDA1C

In the first loop, we get 000001B5B43BD9D0 for malloc() + 0 * (6/2). But in the second copy of the same loop we get ...C for the address. The ...0 result is correct because malloc returns a 16-byte aligned pointer on Windows x64. 0 * (6/2) is 0.

The 3rd column has the same problem.


It looks like the problem is related with the below warning I get at lines 22, 23, 24, 30, 31, 32. When casting the variable l to int64_t, I get rid of this problem.

Warning C26451 Arithmetic overflow: Using operator * on a 4 byte value and then casting the result to a 8 byte value. Cast the value to the wider type before calling operator * to avoid overflow (io.2).

It’s OK, I can fix the problem that way but I’d like to understand what is really going on here. I don’t face this problem with gcc with the same compile flags.

#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

#define N_TESTS 1
#define W 6
#define H 2
int main() {
    int k, l;
    int32_t* mock_ptrs[3];
    int32_t* mock_out_ref[3];
    mock_out_ref[0] = malloc(H * W * sizeof(int32_t));
    mock_out_ref[1] = malloc(H * W * sizeof(int32_t));
    mock_out_ref[2] = malloc(H * W * sizeof(int32_t));

    printf("(1) NOT OK (Line 0 != Line 2) : \n");

    for (k = 0; k < N_TESTS; k++) {
        for (l = 0; l < H; l++) {
            mock_ptrs[0] = mock_out_ref[0] + l * W;
            mock_ptrs[1] = mock_out_ref[1] + l * (W/2);
            mock_ptrs[2] = mock_out_ref[2] + l * (W/2);
            printf("%p %p %p\n", mock_ptrs[0], mock_ptrs[1], mock_ptrs[2]);
        }
    }
    for (k = 0; k < N_TESTS; k++) {
        for (l = 0; l < H; l++) {
            mock_ptrs[0] = mock_out_ref[0] + l * W;
            mock_ptrs[1] = mock_out_ref[1] + l * (W/2);
            mock_ptrs[2] = mock_out_ref[2] + l * (W/2);
            printf("%p %p %p\n", mock_ptrs[0], mock_ptrs[1], mock_ptrs[2]);
        }
    }

    free(mock_out_ref[0]);
    free(mock_out_ref[1]);
    free(mock_out_ref[2]);
    return 0;
}
0

There are 0 best solutions below