https://gcc.gnu.org/bugzilla/show_bug.cgi?id=116026

            Bug ID: 116026
           Summary: Copying or moving a std::variant that can be a vector
                    causes a maybe-uninitialized warning with
                    -fsanitize=address -Og -finline-functions-called-once
           Product: gcc
           Version: 14.1.1
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: sanitizer
          Assignee: unassigned at gcc dot gnu.org
          Reporter: sebastian.r.gracia at gmail dot com
                CC: dodji at gcc dot gnu.org, dvyukov at gcc dot gnu.org,
                    jakub at gcc dot gnu.org, kcc at gcc dot gnu.org
  Target Milestone: ---

How to reproduce:

> cat code.cpp
#include <variant>
#include <vector>

extern "C" int printf(const char *, ...);

using node = std::variant<std::vector<int>, int>;

int main() {
    int a{15};
    [[maybe_unused]] node b = a;        // line 1
    // printf("%d", std::get<int>(b));  // line 2
}


> g++ -Werror=maybe-uninitialized -fsanitize=address -Og 
> -finline-functions-called-once code.cpp
In file included from /usr/include/c++/14.1.1/vector:66,
                 from code.cpp:2:
In destructor ‘std::_Vector_base<_Tp, _Alloc>::~_Vector_base() [with _Tp = int;
_Alloc = std::allocator<int>]’,
    inlined from ‘std::vector<_Tp, _Alloc>::~vector() [with _Tp = int; _Alloc =
std::allocator<int>]’ at /usr/include/c++/14.1.1/bits/stl_vector.h:738:7,
    inlined from ‘constexpr void std::_Destroy(_Tp*) [with _Tp = vector<int>]’
at /usr/include/c++/14.1.1/bits/stl_construct.h:151:22,
    inlined from ‘std::__detail::__variant::_Variant_storage<false,
std::vector<int, std::allocator<int> >, int>::_M_reset()::<lambda(auto:1&&)>
mutable [with auto:1 = std::vector<int>&]’ at
/usr/include/c++/14.1.1/variant:498:19,
    inlined from ‘constexpr _Res std::__invoke_impl(__invoke_other, _Fn&&,
_Args&& ...) [with _Res = void; _Fn =
__detail::__variant::_Variant_storage<false, vector<int, allocator<int> >,
int>::_M_reset()::<lambda(auto:1&&)>; _Args = {vector<int, allocator<int> >&}]’
at /usr/include/c++/14.1.1/bits/invoke.h:61:36,
    inlined from ‘constexpr std::enable_if_t<((bool)is_invocable_r_v<_Res,
_Callable, _Args ...>), _Res> std::__invoke_r(_Callable&&, _Args&& ...) [with
_Res = void; _Callable = __detail::__variant::_Variant_storage<false,
vector<int, allocator<int> >, int>::_M_reset()::<lambda(auto:1&&)>; _Args =
{vector<int, allocator<int> >&}]’ at
/usr/include/c++/14.1.1/bits/invoke.h:111:28,
    inlined from ‘static constexpr decltype(auto)
std::__detail::__variant::__gen_vtable_impl<std::__detail::__variant::_Multi_array<_Result_type
(*)(_Visitor, _Variants ...)>, std::integer_sequence<long unsigned int,
__indices ...> >::__visit_invoke(_Visitor&&, _Variants ...) [with _Result_type
= void; _Visitor = std::__detail::__variant::_Variant_storage<false,
std::vector<int, std::allocator<int> >, int>::_M_reset()::<lambda(auto:1&&)>&&;
_Variants = {std::variant<std::vector<int, std::allocator<int> >, int>&}; long
unsigned int ...__indices = {0}]’ at /usr/include/c++/14.1.1/variant:1064:40,
    inlined from ‘constexpr decltype(auto) std::__do_visit(_Visitor&&,
_Variants&& ...) [with _Result_type = void; _Visitor =
__detail::__variant::_Variant_storage<false, vector<int, allocator<int> >,
int>::_M_reset()::<lambda(auto:1&&)>; _Variants = {variant<vector<int,
allocator<int> >, int>&}]’ at /usr/include/c++/14.1.1/variant:1816:5,
    inlined from ‘constexpr void
std::__detail::__variant::_Variant_storage<false, _Types ...>::_M_reset() [with
_Types = {std::vector<int, std::allocator<int> >, int}]’ at
/usr/include/c++/14.1.1/variant:496:23,
    inlined from ‘std::__detail::__variant::_Variant_storage<false, _Types
...>::~_Variant_storage() [with _Types = {std::vector<int, std::allocator<int>
>, int}]’ at /usr/include/c++/14.1.1/variant:506:17,
    inlined from ‘std::__detail::__variant::_Copy_ctor_base<false,
std::vector<int, std::allocator<int> >, int>::~_Copy_ctor_base()’ at
/usr/include/c++/14.1.1/variant:581:12,
    inlined from ‘std::__detail::__variant::_Move_ctor_base<false,
std::vector<int, std::allocator<int> >, int>::~_Move_ctor_base()’ at
/usr/include/c++/14.1.1/variant:618:12,
    inlined from ‘std::__detail::__variant::_Copy_assign_base<false,
std::vector<int, std::allocator<int> >, int>::~_Copy_assign_base()’ at
/usr/include/c++/14.1.1/variant:656:12,
    inlined from ‘std::__detail::__variant::_Move_assign_base<false,
std::vector<int, std::allocator<int> >, int>::~_Move_assign_base()’ at
/usr/include/c++/14.1.1/variant:708:12,
    inlined from ‘std::__detail::__variant::_Variant_base<std::vector<int,
std::allocator<int> >, int>::~_Variant_base()’ at
/usr/include/c++/14.1.1/variant:762:12,
    inlined from ‘std::variant<_Types>::~variant() [with _Types =
{std::vector<int, std::allocator<int> >, int}]’ at
/usr/include/c++/14.1.1/variant:1435:28,
    inlined from ‘int main()’ at code.cpp:12:1:
/usr/include/c++/14.1.1/bits/stl_vector.h:369:31: error:
‘*(std::_Vector_base<int, std::allocator<int> >*)((char*)&b +
offsetof(std::node, std::variant<std::vector<int, std::allocator<int> >,
int>::<unnamed>.std::__detail::__variant::_Variant_base<std::vector<int,
std::allocator<int> >,
int>::<unnamed>.std::__detail::__variant::_Move_assign_base<false,
std::vector<int, std::allocator<int> >,
int>::<unnamed>.std::__detail::__variant::_Copy_assign_base<false,
std::vector<int, std::allocator<int> >,
int>::<unnamed>.std::__detail::__variant::_Move_ctor_base<false,
std::vector<int, std::allocator<int> >,
int>::<unnamed>.std::__detail::__variant::_Copy_ctor_base<false,
std::vector<int, std::allocator<int> >,
int>::<unnamed>.std::__detail::__variant::_Variant_storage<false,
std::vector<int, std::allocator<int> >, int>::_M_u)).std::_Vector_base<int,
std::allocator<int> >::_M_impl.std::_Vector_base<int, std::allocator<int>
>::_Vector_impl::std::_Vector_base<int, std::allocator<int>
>::_Vector_impl_data.std::_Vector_base<int, std::allocator<int>
>::_Vector_impl_data::_M_end_of_storage’ may be used uninitialized
[-Werror=maybe-uninitialized]
  369 |                       _M_impl._M_end_of_storage - _M_impl._M_start);
      |                       ~~~~~~~~^~~~~~~~~~~~~~~~~
code.cpp: In function ‘int main()’:
code.cpp:10:27: note: ‘b’ declared here
   10 |     [[maybe_unused]] node b = a;        // line 1
      |                           ^
cc1plus: some warnings being treated as errors

> g++ -v
Using built-in specs.
COLLECT_GCC=g++
COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-pc-linux-gnu/14.1.1/lto-wrapper
Target: x86_64-pc-linux-gnu
Configured with: /build/gcc/src/gcc/configure
--enable-languages=ada,c,c++,d,fortran,go,lto,m2,objc,obj-c++,rust
--enable-bootstrap --prefix=/usr --libdir=/usr/lib --libexecdir=/usr/lib
--mandir=/usr/share/man --infodir=/usr/share/info
--with-bugurl=https://gitlab.archlinux.org/archlinux/packaging/packages/gcc/-/issues
--with-build-config=bootstrap-lto --with-linker-hash-style=gnu
--with-system-zlib --enable-__cxa_atexit --enable-cet=auto
--enable-checking=release --enable-clocale=gnu --enable-default-pie
--enable-default-ssp --enable-gnu-indirect-function --enable-gnu-unique-object
--enable-libstdcxx-backtrace --enable-link-serialization=1
--enable-linker-build-id --enable-lto --enable-multilib --enable-plugin
--enable-shared --enable-threads=posix --disable-libssp --disable-libstdcxx-pch
--disable-werror
Thread model: posix
Supported LTO compression algorithms: zlib zstd
gcc version 14.1.1 20240522 (GCC)

Weird behaviors noticed:
- Using -fsanitize=address,undefined causes no warning
- Defining _GLIBCXX_DEBUG (with -D_GLIBCXX_DEBUG) negates the issue
- Warning persists when changing 'line 1' to use std::move (identical except
for note at bottom and line number changes from including <utility>)
- No compile warning is issued when 'line 2' is uncommented
- When adding another line that uses std::move, no warning is issued, despite
both lines causing the warnings on their own

I used to have a related version of this issue with a different core
warning/error, but I can no longer reproduce it. All I can remember is that it
was also a maybe-uninitialized warning, and that it concerned an assignment
statement instead of a subtraction expression. Additionally, in that issue,
using a struct inheriting from std::variant, with 'using variant::variant;'
inside, caused the warning, whereas a using-declaration did not. It was
probably in an older version of gcc, though I can't say for sure.
  • [Bug sanitizer/116026] Ne... sebastian.r.gracia at gmail dot com via Gcc-bugs

Reply via email to