warning: operator delete called on unallocated object
Asked Answered
T

1

15

I'm trying to compile the following code (this is a minimal example), but I get a warning I can't figure out:

#include <string>
#include <variant>
#include <vector>

struct Bar {
  std::wstring x = L"";
}; 

Bar Foo() {
  std::variant<std::vector<int>, Bar> tmp = Bar();
  if (std::holds_alternative<Bar>(tmp)) return std::move(std::get<Bar>(tmp));
  return Bar();
}

I'm trying to build this with g++ -std=c++20 -Wall -Wextra -O2 /tmp/test.cc -c

I get the following warning:

In file included from /usr/include/x86_64-linux-gnu/c++/12/bits/c++allocator.h:33,
                 from /usr/include/c++/12/bits/allocator.h:46,
                 from /usr/include/c++/12/string:41,
                 from /tmp/test.cc:1:
In member function ‘void std::__new_allocator<_Tp>::deallocate(_Tp*, size_type) [with _Tp = int]’,
    inlined from ‘constexpr void std::allocator< <template-parameter-1-1> >::deallocate(_Tp*, std::size_t) [with _Tp = int]’ at /usr/include/c++/12/bits/allocator.h:200:35,
    inlined from ‘static constexpr void std::allocator_traits<std::allocator<_CharT> >::deallocate(allocator_type&, pointer, size_type) [with _Tp = int]’ at /usr/include/c++/12/bits/alloc_traits.h:496:23,
    inlined from ‘constexpr void std::_Vector_base<_Tp, _Alloc>::_M_deallocate(pointer, std::size_t) [with _Tp = int; _Alloc = std::allocator<int>]’ at /usr/include/c++/12/bits/stl_vector.h:387:19,
    inlined from ‘constexpr std::_Vector_base<_Tp, _Alloc>::~_Vector_base() [with _Tp = int; _Alloc = std::allocator<int>]’ at /usr/include/c++/12/bits/stl_vector.h:366:15,
    inlined from ‘constexpr std::vector<_Tp, _Alloc>::~vector() [with _Tp = int; _Alloc = std::allocator<int>]’ at /usr/include/c++/12/bits/stl_vector.h:733:7,
    inlined from ‘constexpr void std::destroy_at(_Tp*) [with _Tp = vector<int>]’ at /usr/include/c++/12/bits/stl_construct.h:88:18,
    inlined from ‘constexpr void std::_Destroy(_Tp*) [with _Tp = vector<int>]’ at /usr/include/c++/12/bits/stl_construct.h:149:22,
    inlined from ‘std::__detail::__variant::_Variant_storage<false, std::vector<int, std::allocator<int> >, Bar>::_M_reset()::<lambda(auto:11&&)> mutable [with auto:11 = std::vector<int>&]’ at /usr/include/c++/12/variant:472: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> >, Bar>::_M_reset()::<lambda(auto:11&&)>; _Args = {vector<int, allocator<int> >&}]’ at /usr/include/c++/12/bits/invoke.h:61:36,
    inlined from ‘constexpr std::enable_if_t<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> >, Bar>::_M_reset()::<lambda(auto:11&&)>; _Args = {vector<int, allocator<int> >&}]’ at /usr/include/c++/12/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> >, Bar>::_M_reset()::<lambda(auto:11&&)>&&; _Variants = {std::variant<std::vector<int, std::allocator<int> >, Bar>&}; long unsigned int ...__indices = {0}]’ at /usr/include/c++/12/variant:1035: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> >, Bar>::_M_reset()::<lambda(auto:11&&)>; _Variants = {variant<vector<int, allocator<int> >, Bar>&}]’ at /usr/include/c++/12/variant:1783:5,
    inlined from ‘constexpr void std::__detail::__variant::_Variant_storage<false, _Types ...>::_M_reset() [with _Types = {std::vector<int, std::allocator<int> >, Bar}]’ at /usr/include/c++/12/variant:470:23,
    inlined from ‘constexpr std::__detail::__variant::_Variant_storage<false, _Types ...>::~_Variant_storage() [with _Types = {std::vector<int, std::allocator<int> >, Bar}]’ at /usr/include/c++/12/variant:480:17,
    inlined from ‘constexpr std::__detail::__variant::_Copy_ctor_base<false, std::vector<int, std::allocator<int> >, Bar>::~_Copy_ctor_base()’ at /usr/include/c++/12/variant:554:12,
    inlined from ‘constexpr std::__detail::__variant::_Move_ctor_base<false, std::vector<int, std::allocator<int> >, Bar>::~_Move_ctor_base()’ at /usr/include/c++/12/variant:591:12,
    inlined from ‘constexpr std::__detail::__variant::_Copy_assign_base<false, std::vector<int, std::allocator<int> >, Bar>::~_Copy_assign_base()’ at /usr/include/c++/12/variant:629:12,
    inlined from ‘constexpr std::__detail::__variant::_Move_assign_base<false, std::vector<int, std::allocator<int> >, Bar>::~_Move_assign_base()’ at /usr/include/c++/12/variant:681:12,
    inlined from ‘constexpr std::__detail::__variant::_Variant_base<std::vector<int, std::allocator<int> >, Bar>::~_Variant_base()’ at /usr/include/c++/12/variant:735:12,
    inlined from ‘constexpr std::variant<_Types>::~variant() [with _Types = {std::vector<int, std::allocator<int> >, Bar}]’ at /usr/include/c++/12/variant:1407:28,
    inlined from ‘Bar Foo()’ at /tmp/test.cc:13:1:
/usr/include/c++/12/bits/new_allocator.h:158:33: warning: ‘void operator delete(void*, std::size_t)’ called on unallocated object ‘tmp’ [-Wfree-nonheap-object]
  158 |         _GLIBCXX_OPERATOR_DELETE(_GLIBCXX_SIZED_DEALLOC(__p, __n));
      |                                 ^
/tmp/test.cc: In function ‘Bar Foo()’:
/tmp/test.cc:10:39: note: declared here
   10 |   std::variant<std::vector<int>, Bar> tmp = Bar();
      |                                       ^~~

g++ --version says g++ (Debian 12.2.0-10) 12.2.0

I know this code, as is, doesn't make that much sense; but it also shouldn't have this problem: this is a minimal example that exhibits this warning, of a much more complex function.

Strangely, the warning disappears if I do any of the following:

  1. Change Bar::x to be a std::string.
  2. Change tmp to be std::variant<int, Bar> (rather than having a std::vector<int> as the first type).
  3. Remove g++ command-line flag -O2 (i.e., compile with g++ -std=c++20 -Wall -Wextra -O2 /tmp/test.cc -c).

Why would any of these changes make the warning go away!?

If I build this with --std=c++17, the problem remains.

Thankyou answered 4/2, 2023 at 21:9 Comment(7)
gcc 12? This is likely to be another case of bogus optimizer warnings from recent versions of gcc, that have trickled in over the last couple of months.Diminished
It also goes away if you get rid of the std::move, which I don't think is needed there: godbolt.org/z/je7dKEGd6Margueritamarguerite
It also goes away if you turn off optimizations.Appetency
It went away for me when I made the Foo function static...Lengthwise
@Margueritamarguerite : It is needed if you want to move-construct rather than copy-construct the return value – std::get returns an lvalue when given an lvalue. However, this would be more idiomatically written as return std::get<Bar>(std::move(tmp)); IMOSquat
@Squat Wouldn't RVO and copy elision work without the std::move? Whenever I see a return std::move... I think it may "inhibit" the copy elision by specifying std::move.Margueritamarguerite
@Margueritamarguerite : That's a good instinct, but it only applies to returning local variables directly by name (you can see the details here). In this case what's being returned is the result of a function call, so there is no automatic move or RVO; and said function returns a reference, so there is no opportunity for copy elision (which only works for prvalues).Squat
V
10

The -Wfree-nonheap-object flag of gcc has a series of false positives bugs, among which bug 99098 is used to record these meta-bugs.

The bug in your example is similar to bug 108088 and has been listed, which issues a false positive warning message since gcc-12.

Val answered 5/2, 2023 at 2:51 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.