Search code examples
c++gccvisual-c++undefined-behaviordereference

Undefined behaviour accessing const ptr sometimes


I have a header file defined as

#pragma once
#include <iostream>

template<int size>
struct B
{
    double arr[size * size];

    constexpr B() : arr()
    {
        arr[0] = 1.;
    }
};

template<int size>
struct A
{
    const double* arr = B<size>().arr;

    void print()
    {
        // including this statement also causes undefined behaviour on subsequent lines
        //printf("%i\n", arr);

        printf("%f\n", arr[0]);
        printf("%f\n", arr[0]); // ???

        // prevent optimisation
        for (int i = 0; i < size * size; i++)
            printf("%f ", arr[i]);
    }
};

and call it with

auto a = A<8>();
a.print();

Now this code only runs expectedly when compiled with msvc release mode (all compiled with c++17).

expected output:

1.000000
1.000000

msvc debug:

1.000000
-92559631349317830736831783200707727132248687965119994463780864.000000

gcc via mingw (with and without -g):

1.000000
0.000000

However, this behaviour is inconsistent. The expected output is given if I replace double arr[size * size] with double arr[size] instead. No more problems if I allocate arr on the heap of course.

I looked at the assembly of the msvc debug build but I don't see anything out of the ordinary. Why does this undefined behaviour only occur sometimes?

asm output

decompiled msvc release


Solution

  • It seems that it was completely coincidental that smaller allocations were always addressed in a spot that would not get erased by the rep stosd instruction present in printf. Not caused by strange compiler optimisations as I first thought it was.

    What does the "rep stos" x86 assembly instruction sequence do?

    I also have no idea why I decided to do it this way. Not exactly the question I asked but I ultimately wanted a compile time lookup table so the real solution was static inline constexpr auto arr = B<size>() on c++20. Which is why the code looks strange.