]> git.hungrycats.org Git - bees/commitdiff
progress: work around GCC-16 -Warray-bounds bug
authorZygo Blaxell <bees@furryterror.org>
Sun, 3 May 2026 18:52:19 +0000 (14:52 -0400)
committerZygo Blaxell <bees@furryterror.org>
Sun, 3 May 2026 22:18:18 +0000 (18:18 -0400)
`make_shared<ProgressTrackerState>()` keeps triggering GCC bugs.
The latest failure on GCC-16.0 and GCC-16.1:

/usr/include/c++/16.1.1/bits/stl_tree.h:1383:19: error: array subscript 1 is outside array bounds of ‘std::_Sp_counted_ptr_inplace<crucible::ProgressTracker<long unsigned int>::ProgressHolderState, std::allocator<void>, __gnu_cxx::_S_atomic> [1]’ [-Werror=array-bounds=]
../include/crucible/progress.h:46:24: error: array subscript ‘crucible::ProgressTracker<long unsigned int>::ProgressTrackerState[0]’ is partly outside array bounds of ‘unsigned char [40]’ [-Werror=array-bounds=]

The regression is already reported to the GCC project:

https://www.mail-archive.com/gcc-bugs%40gcc.gnu.org/msg895281.html
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=123912
(and its duplicates)

The problem is that GCC's static analyzer forgets that make_shared
intentionally allocated a control block and an object in the same
allocation, and thinks that accesses beyond the end of the control block
are out-of-bounds array accesses.

This workaround is the shortest:  start with a unique_ptr (which has no
control block but does have an exception-safe allocator), then convert
to shared_ptr.  This breaks the allocation into two parts so that GCC
is no longer confused.  As there are typically fewer than 10k progress
tracking items, the separate control blocks will only add a few hundred
KiB of RAM usage.

Signed-off-by: Zygo Blaxell <bees@furryterror.org>
include/crucible/progress.h

index a9fd003f9efb90fe6be8d534f760f3e11a2d0ab2..9d27b6366185fc2e528620c11bda577e15f655d7 100644 (file)
@@ -90,7 +90,7 @@ namespace crucible {
 
        template <class T>
        ProgressTracker<T>::ProgressTracker(const ProgressTracker::value_type &t) :
-               m_state(make_shared<ProgressTrackerState>())
+               m_state(make_unique<ProgressTrackerState>())
        {
                m_state->m_begin = t;
                m_state->m_end = t;