Bug 2507952

Summary: Bogus array bounds warning in shared_ptr_base.h
Product: [Fedora] Fedora Reporter: Tom Hughes <tom>
Component: gccAssignee: Jakub Jelinek <jakub>
Status: NEW --- QA Contact: Fedora Extras Quality Assurance <extras-qa>
Severity: medium Docs Contact:
Priority: unspecified    
Version: 44CC: dmalcolm, fweimer, jakub, jlaw, josmyers, jwakely, mcermak, mpolacek, msebor, nickc, nixuser, sipoyare
Target Milestone: ---   
Target Release: ---   
Hardware: Unspecified   
OS: Linux   
URL: https://godbolt.org/z/G4WbTxxzT
Whiteboard:
Fixed In Version: Doc Type: ---
Doc Text:
Story Points: ---
Clone Of: Environment:
Last Closed: Type: ---
Regression: --- Mount Type: ---
Documentation: --- CRM:
Verified Versions: Category: ---
oVirt Team: --- RHEL 7.3 requirements from Atomic Host:
Cloudforms Team: --- Target Upstream Version:
Embargoed:
Attachments:
Description Flags
Test case none

Description Tom Hughes 2026-07-28 10:18:28 UTC
This occurs with gcc-16.1.1-2.fc44.x86_64 at O2 and above.

Testing on godbolt reproduces it in gcc 16 and trunk but not in gcc 15.

As best I can tell the summary is that constructing a std::shared_ptr with a custom free function and then later constructing one for a different type that doesn't use a custom free function causes bogus array bounds warnings in that second pointer's destructor.

Reproducible: Always

Steps to Reproduce:
1. Save the attached file as test.cpp and compile with "g++ -std=c++23 -O2 -Wall -Werror test.cpp"
Actual Results:
In file included from /usr/include/c++/16/bits/shared_ptr.h:53,
                 from /usr/include/c++/16/memory:82,
                 from test.cpp:1:
In member function ‘void std::_Sp_counted_deleter<_Ptr, _Deleter, _Alloc, _Lp>::_M_dispose() [with _Ptr = value*; _Deleter = void (*)(value*); _Alloc = std::allocator<void>; __gnu_cxx::_Lock_policy _Lp = __gnu_cxx::_S_atomic]’,
    inlined from ‘void std::_Sp_counted_base<_Lp>::_M_release() [with __gnu_cxx::_Lock_policy _Lp = __gnu_cxx::_S_atomic]’ at /usr/include/c++/16/bits/shared_ptr_base.h:423:18,
    inlined from ‘void std::_Sp_counted_base<_Lp>::_M_release() [with __gnu_cxx::_Lock_policy _Lp = __gnu_cxx::_S_atomic]’ at /usr/include/c++/16/bits/shared_ptr_base.h:392:5,
    inlined from ‘std::__shared_count<_Lp>::~__shared_count() [with __gnu_cxx::_Lock_policy _Lp = __gnu_cxx::_S_atomic]’ at /usr/include/c++/16/bits/shared_ptr_base.h:1136:21,
    inlined from ‘std::__shared_ptr<_Tp, _Lp>::~__shared_ptr() [with _Tp = baz; __gnu_cxx::_Lock_policy _Lp = __gnu_cxx::_S_atomic]’ at /usr/include/c++/16/bits/shared_ptr_base.h:1610:7,
    inlined from ‘std::shared_ptr<baz>::~shared_ptr()’ at /usr/include/c++/16/bits/shared_ptr.h:175:11,
    inlined from ‘void bar()’ at test.cpp:27:1:
/usr/include/c++/16/bits/shared_ptr_base.h:590:25: error: array subscript ‘std::_Sp_counted_deleter<value*, void (*)(value*), std::allocator<void>, __gnu_cxx::_S_atomic>[0]’ is partly outside array bounds of ‘unsigned char [24]’ [-Werror=array-bounds=]
  590 |       { _M_impl._M_del()(_M_impl._M_ptr); }
      |         ~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~
In constructor ‘std::__shared_count<_Lp>::__shared_count(_Ptr) [with _Ptr = baz*; __gnu_cxx::_Lock_policy _Lp = __gnu_cxx::_S_atomic]’,
    inlined from ‘std::__shared_count<_Lp>::__shared_count(_Ptr, std::false_type) [with _Ptr = baz*; __gnu_cxx::_Lock_policy _Lp = __gnu_cxx::_S_atomic]’ at /usr/include/c++/16/bits/shared_ptr_base.h:992:22,
    inlined from ‘std::__shared_ptr<_Tp, _Lp>::__shared_ptr(_Yp*) [with _Yp = baz; <template-parameter-2-2> = void; _Tp = baz; __gnu_cxx::_Lock_policy _Lp = __gnu_cxx::_S_atomic]’ at /usr/include/c++/16/bits/shared_ptr_base.h:1555:17,
    inlined from ‘std::shared_ptr<_Tp>::shared_ptr(_Yp*) [with _Yp = baz; <template-parameter-2-2> = void; _Tp = baz]’ at /usr/include/c++/16/bits/shared_ptr.h:213:46,
    inlined from ‘void bar()’ at test.cpp:26:7:
/usr/include/c++/16/bits/shared_ptr_base.h:981:23: note: object of size 24 allocated by ‘operator new’
  981 |               _M_pi = new _Sp_counted_ptr<_Ptr, _Lp>(__p);
      |                       ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
In destructor ‘std::_Sp_counted_deleter<_Ptr, _Deleter, _Alloc, _Lp>::~_Sp_counted_deleter() [with _Ptr = value*; _Deleter = void (*)(value*); _Alloc = std::allocator<void>; __gnu_cxx::_Lock_policy _Lp = __gnu_cxx::_S_atomic]’,
    inlined from ‘void std::_Sp_counted_deleter<_Ptr, _Deleter, _Alloc, _Lp>::_M_destroy() [with _Ptr = value*; _Deleter = void (*)(value*); _Alloc = std::allocator<void>; __gnu_cxx::_Lock_policy _Lp = __gnu_cxx::_S_atomic]’ at /usr/include/c++/16/bits/shared_ptr_base.h:597:28,
    inlined from ‘void std::_Sp_counted_base<_Lp>::_M_release() [with __gnu_cxx::_Lock_policy _Lp = __gnu_cxx::_S_atomic]’ at /usr/include/c++/16/bits/shared_ptr_base.h:424:18,
    inlined from ‘void std::_Sp_counted_base<_Lp>::_M_release() [with __gnu_cxx::_Lock_policy _Lp = __gnu_cxx::_S_atomic]’ at /usr/include/c++/16/bits/shared_ptr_base.h:392:5,
    inlined from ‘std::__shared_count<_Lp>::~__shared_count() [with __gnu_cxx::_Lock_policy _Lp = __gnu_cxx::_S_atomic]’ at /usr/include/c++/16/bits/shared_ptr_base.h:1136:21,
    inlined from ‘std::__shared_ptr<_Tp, _Lp>::~__shared_ptr() [with _Tp = baz; __gnu_cxx::_Lock_policy _Lp = __gnu_cxx::_S_atomic]’ at /usr/include/c++/16/bits/shared_ptr_base.h:1610:7,
    inlined from ‘std::shared_ptr<baz>::~shared_ptr()’ at /usr/include/c++/16/bits/shared_ptr.h:175:11,
    inlined from ‘void bar()’ at test.cpp:27:1:
/usr/include/c++/16/bits/shared_ptr_base.h:585:41: error: array subscript ‘std::_Sp_counted_deleter<value*, void (*)(value*), std::allocator<void>, __gnu_cxx::_S_atomic>[0]’ is partly outside array bounds of ‘unsigned char [24]’ [-Werror=array-bounds=]
  585 |       ~_Sp_counted_deleter() noexcept { }
      |                                         ^
In constructor ‘std::__shared_count<_Lp>::__shared_count(_Ptr) [with _Ptr = baz*; __gnu_cxx::_Lock_policy _Lp = __gnu_cxx::_S_atomic]’,
    inlined from ‘std::__shared_count<_Lp>::__shared_count(_Ptr, std::false_type) [with _Ptr = baz*; __gnu_cxx::_Lock_policy _Lp = __gnu_cxx::_S_atomic]’ at /usr/include/c++/16/bits/shared_ptr_base.h:992:22,
    inlined from ‘std::__shared_ptr<_Tp, _Lp>::__shared_ptr(_Yp*) [with _Yp = baz; <template-parameter-2-2> = void; _Tp = baz; __gnu_cxx::_Lock_policy _Lp = __gnu_cxx::_S_atomic]’ at /usr/include/c++/16/bits/shared_ptr_base.h:1555:17,
    inlined from ‘std::shared_ptr<_Tp>::shared_ptr(_Yp*) [with _Yp = baz; <template-parameter-2-2> = void; _Tp = baz]’ at /usr/include/c++/16/bits/shared_ptr.h:213:46,
    inlined from ‘void bar()’ at test.cpp:26:7:
/usr/include/c++/16/bits/shared_ptr_base.h:981:23: note: object of size 24 allocated by ‘operator new’
  981 |               _M_pi = new _Sp_counted_ptr<_Ptr, _Lp>(__p);
      |                       ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
In destructor ‘std::_Sp_counted_deleter<_Ptr, _Deleter, _Alloc, _Lp>::~_Sp_counted_deleter() [with _Ptr = value*; _Deleter = void (*)(value*); _Alloc = std::allocator<void>; __gnu_cxx::_Lock_policy _Lp = __gnu_cxx::_S_atomic]’,
    inlined from ‘std::_Sp_counted_deleter<_Ptr, _Deleter, _Alloc, _Lp>::~_Sp_counted_deleter() [with _Ptr = value*; _Deleter = void (*)(value*); _Alloc = std::allocator<void>; __gnu_cxx::_Lock_policy _Lp = __gnu_cxx::_S_atomic]’ at /usr/include/c++/16/bits/shared_ptr_base.h:585:41,
    inlined from ‘void std::_Sp_counted_base<_Lp>::_M_destroy() [with __gnu_cxx::_Lock_policy _Lp = __gnu_cxx::_S_atomic]’ at /usr/include/c++/16/bits/shared_ptr_base.h:143:9,
    inlined from ‘void std::_Sp_counted_base<_Lp>::_M_release() [with __gnu_cxx::_Lock_policy _Lp = __gnu_cxx::_S_atomic]’ at /usr/include/c++/16/bits/shared_ptr_base.h:424:18,
    inlined from ‘void std::_Sp_counted_base<_Lp>::_M_release() [with __gnu_cxx::_Lock_policy _Lp = __gnu_cxx::_S_atomic]’ at /usr/include/c++/16/bits/shared_ptr_base.h:392:5,
    inlined from ‘std::__shared_count<_Lp>::~__shared_count() [with __gnu_cxx::_Lock_policy _Lp = __gnu_cxx::_S_atomic]’ at /usr/include/c++/16/bits/shared_ptr_base.h:1136:21,
    inlined from ‘std::__shared_ptr<_Tp, _Lp>::~__shared_ptr() [with _Tp = baz; __gnu_cxx::_Lock_policy _Lp = __gnu_cxx::_S_atomic]’ at /usr/include/c++/16/bits/shared_ptr_base.h:1610:7,
    inlined from ‘std::shared_ptr<baz>::~shared_ptr()’ at /usr/include/c++/16/bits/shared_ptr.h:175:11,
    inlined from ‘void bar()’ at test.cpp:27:1:
/usr/include/c++/16/bits/shared_ptr_base.h:585:41: error: array subscript ‘std::_Sp_counted_deleter<value*, void (*)(value*), std::allocator<void>, __gnu_cxx::_S_atomic>[0]’ is partly outside array bounds of ‘unsigned char [24]’ [-Werror=array-bounds=]
  585 |       ~_Sp_counted_deleter() noexcept { }
      |                                         ^
In constructor ‘std::__shared_count<_Lp>::__shared_count(_Ptr) [with _Ptr = baz*; __gnu_cxx::_Lock_policy _Lp = __gnu_cxx::_S_atomic]’,
    inlined from ‘std::__shared_count<_Lp>::__shared_count(_Ptr, std::false_type) [with _Ptr = baz*; __gnu_cxx::_Lock_policy _Lp = __gnu_cxx::_S_atomic]’ at /usr/include/c++/16/bits/shared_ptr_base.h:992:22,
    inlined from ‘std::__shared_ptr<_Tp, _Lp>::__shared_ptr(_Yp*) [with _Yp = baz; <template-parameter-2-2> = void; _Tp = baz; __gnu_cxx::_Lock_policy _Lp = __gnu_cxx::_S_atomic]’ at /usr/include/c++/16/bits/shared_ptr_base.h:1555:17,
    inlined from ‘std::shared_ptr<_Tp>::shared_ptr(_Yp*) [with _Yp = baz; <template-parameter-2-2> = void; _Tp = baz]’ at /usr/include/c++/16/bits/shared_ptr.h:213:46,
    inlined from ‘void bar()’ at test.cpp:26:7:
/usr/include/c++/16/bits/shared_ptr_base.h:981:23: note: object of size 24 allocated by ‘operator new’
  981 |               _M_pi = new _Sp_counted_ptr<_Ptr, _Lp>(__p);
      |                       ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
cc1plus: all warnings being treated as errors


Expected Results:
File compiles.

Comment 1 Tom Hughes 2026-07-28 10:19:15 UTC
Created attachment 2152817 [details]
Test case

Comment 2 Jonathan Wakely 2026-07-29 18:17:28 UTC
I pushed a workaround upstream.