Home > Blockchain >  Undefined behaviour accessing const ptr sometimes
Undefined behaviour accessing const ptr sometimes

Time:03-11

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

CodePudding user response:

In this declaration

const double* arr = B<size>().arr;

there is declared a pointer to (the first element of ) a temporary array that will not be alive after the declaration

So dereferencing the pointer results in undefined behavior.

CodePudding user response:

When you wrote:

const double* arr = B<size>().arr;

The above statement initializes a pointer to const double i.e., const double* named arr with a temporary array object. Since this temporary array object will be destroyed at the end of the full-expression, using arr will lead to undefined behavior.

Why does this undefined behaviour only occur sometimes?

Undefined behavior means anything1 can happen including but not limited to the program giving your expected output. But never rely(or make conclusions based) on the output of a program that has undefined behavior.

So the output that you're seeing(maybe seeing) is a result of undefined behavior. And as i said don't rely on the output of a program that has UB. The program may just crash.

So the first step to make the program correct would be to remove UB. Then and only then you can start reasoning about the output of the program.


1For a more technically accurate definition of undefined behavior see this where it is mentioned that: there are no restrictions on the behavior of the program.

CodePudding user response:

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.

  • Related