2

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;
}
Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
  • 3
    Can you reduce the code a bit? I don't understand, why you repeat the loop. – Gerhard Stein Mar 13 '20 at 10:14
  • 3
    What exactly is the bug you think you have, and what does this have to do with AVX2? Also, why is this tagged C and C++? Which language are you compiling this code as? Especially if it's C++, prefer `static const size_t W = whatever;` over a `#define` - that will silence the warning. Although the warning should be irrelevant for the small `l` and `W` values you're testing with, so it doesn't make any sense that there'd be a difference (unless you've found a compiler bug) – Peter Cordes Mar 13 '20 at 10:26
  • 3
    File a bug (menu Help/Send Feedback/Report a Problem...). – Werner Henze Mar 13 '20 at 10:58
  • I have filed a bug already. I am repeating the loop to show that the mock_ptrs I have are not the same after the first and second loop. This is only happening when I set /O2, /Ob2, /arch:AVX2 flags. I am compiling the code as C... – addeconinck Mar 18 '20 at 09:23
  • 1
    The question could be answered by "This is a compiler bug" – M.M Mar 18 '20 at 22:26
  • @M.M: Until I took the time to read through the question and code carefully, and edit, it wasn't at all clear exactly what the claimed problem was. It looked like it might be saying that getting the warning was a bug, which it isn't, and didn't mention any details about what exactly was wrong with the output. But yes, now it's clearly a compiler bug. – Peter Cordes Mar 18 '20 at 23:46
  • @PeterCordes the problem could be seen in that running the exact same arithmetic twice produced different output (which OP pointed out in their second paragraph) – M.M Mar 18 '20 at 23:48

0 Answers0