Marko Filipovic
Marko Filipovic

Reputation: 53

Why does g++ 11 trigger "maybe uninitialized" warning in connection with this pointer casting

After a compiler update from g++ v7.5 (Ubuntu 18.04) to v11.2 (Ubuntu 22.04), the following code triggers the maybe-uninitialized warning:

#include <cstdint>

void f(std::uint16_t v)
{
  (void) v;
}

int main()
{
    unsigned int pixel = 0;
    std::uint16_t *f16p = reinterpret_cast<std::uint16_t*>(&pixel);
    f(*f16p);
}

Compiling on Ubuntu 22.04, g++ v11.2 with -O3 -Wall -Werror.

The example code is a reduced form of a real use case, and its ugliness is not the issue here.

Since we have -Werror enabled, it leads to a build error, so I'm trying figure out how to deal with it right now. Is this an instance of this gcc bug, or is there an other explanation for the warning?

https://godbolt.org/z/baaMTxhae

Upvotes: 2

Views: 331

Answers (1)

Artyer
Artyer

Reputation: 40836

You don't initialize an object of type std::uint16_t, so it is used uninitialized.

This error is suppressed by -fno-strict-aliasing, allowing pixel to be accessed through a uint16_t lvalue. Note that -fstrict-aliasing is the default at -O2 or higher.
It could also be fixed with a may_alias pointer:

using aliasing_uint16_t = std::uint16_t [[gnu::may_alias]];
aliasing_uint16_t* f16p = reinterpret_cast<std::uint16_t*>(&pixel);
f(*f16p);

Or you can use std::start_lifetime_as:

static_assert(sizeof(int) >= sizeof(std::uint16_t) && alignof(int) >= alignof(std::uint16_t));

// (C++23, not implemented in g++11 or 12 yet)
auto *f16p = std::start_lifetime_as<std::uint16_t>(&pixel);

// (C++17)
auto *f16p = std::launder(reinterpret_cast<std::uint16_t*>(new (&pixel) char[sizeof(std::uint16_t)]));

Upvotes: 2

Related Questions