Bug 2507952 - Bogus array bounds warning in shared_ptr_base.h
Summary: Bogus array bounds warning in shared_ptr_base.h
Keywords:
Status: NEW
Alias: None
Product: Fedora
Classification: Fedora
Component: gcc
Version: 44
Hardware: Unspecified
OS: Linux
unspecified
medium
Target Milestone: ---
Assignee: Jakub Jelinek
QA Contact: Fedora Extras Quality Assurance
URL: https://godbolt.org/z/G4WbTxxzT
Whiteboard:
Depends On:
Blocks:
TreeView+ depends on / blocked
 
Reported: 2026-07-28 10:18 UTC by Tom Hughes
Modified: 2026-07-29 18:17 UTC (History)
12 users (show)

Fixed In Version:
Clone Of:
Environment:
Last Closed:
Type: ---
Embargoed:


Attachments (Terms of Use)
Test case (404 bytes, text/x-csrc)
2026-07-28 10:19 UTC, Tom Hughes
no flags Details


Links
System ID Private Priority Status Summary Last Updated
GNU Compiler Collection 122197 0 None None None 2026-07-28 15:46:30 UTC

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.


Note You need to log in before you can comment on or make changes to this bug.