https://gcc.gnu.org/bugzilla/show_bug.cgi?id=127140
Bug ID: 127140
Summary: analyzer reports false positives with
std::unordered_map
Product: gcc
Version: 15.2.0
Status: UNCONFIRMED
Severity: normal
Priority: P3
Component: analyzer
Assignee: dmalcolm at gcc dot gnu.org
Reporter: sudolskym at gmail dot com
Target Milestone: ---
Target: x86_64-pc-linux-gnu (Ubuntu 24.04.4 LTS)
Configured with: ../gcc-15-source/configure --prefix=/opt/gcc-15
--disable-multilib --enable-languages=c++
gcc version 15.2.0 (GCC)
Page https://gcc.gnu.org/bugs/ says to post preprocessed file (*.i*) instead of
source but that has 1 MB while original source is minimalistic, self-contained
and short:
#include <unordered_map>
int main()
{
std::unordered_map<int, int> x;
x[10] = 10;
}
g++ -std=c++26 -Wall -Wextra -Wpedantic -fanalyzer a.cpp
In file included from
/opt/gcc-15/include/c++/15.2.0/x86_64-pc-linux-gnu/bits/c++allocator.h:33,
from /opt/gcc-15/include/c++/15.2.0/bits/allocator.h:46,
from /opt/gcc-15/include/c++/15.2.0/bits/alloc_traits.h:39,
from /opt/gcc-15/include/c++/15.2.0/ext/alloc_traits.h:36,
from
/opt/gcc-15/include/c++/15.2.0/bits/hashtable_policy.h:39,
from /opt/gcc-15/include/c++/15.2.0/bits/hashtable.h:37,
from /opt/gcc-15/include/c++/15.2.0/bits/unordered_map.h:33,
from /opt/gcc-15/include/c++/15.2.0/unordered_map:43,
from a.cpp:3:
In member function ‘constexpr std::__new_allocator<_Tp>::size_type
std::__new_allocator<_Tp>::_M_max_size() const [with _Tp =
std::__detail::_Hash_node<std::pair<const int, int>, false>]’,
inlined from ‘_Tp* std::__new_allocator<_Tp>::allocate(size_type, const
void*) [with _Tp = std::__detail::_Hash_node<std::pair<const int, int>,
false>]’ at /opt/gcc-15/include/c++/15.2.0/bits/new_allocator.h:134:46:
/opt/gcc-15/include/c++/15.2.0/bits/new_allocator.h:233:57: warning: leak of
‘__a->std::__new_allocator<std::__detail::_Hash_node<std::pair<const int, int>,
false> >::allocate(__n, 0)’ [CWE-401] [-Wanalyzer-malloc-leak]
233 | return std::size_t(__PTRDIFF_MAX__) / sizeof(_Tp);
| ^
‘std::__detail::_Hashtable_alloc<_NodeAlloc>::__node_type*
std::__detail::_Hashtable_alloc<_NodeAlloc>::_M_allocate_node(_Args&& ...)
[with _Args = {const std::piecewise_construct_t&, std::tuple<int&&>,
std::tuple<>}; _NodeAlloc =
std::allocator<std::__detail::_Hash_node<std::pair<const int, int>, false> >]’:
events 1-2
│
│/opt/gcc-15/include/c++/15.2.0/bits/hashtable_policy.h:1547:7:
│ 1547 | _Hashtable_alloc<_NodeAlloc>::_M_allocate_node(_Args&&...
__args)
│ | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~
│ | |
│ | (1) entry to
‘std::__detail::_Hashtable_alloc<std::allocator<std::__detail::_Hash_node<std::pair<const
int, int>, false> > >::_M_allocate_node<const std::piecewise_construct_t&,
std::tuple<int&&>, std::tuple<> >’
│......
│ 1551 | auto __nptr = __node_alloc_traits::allocate(__alloc, 1);
│ | ~
│ | |
│ | (2) inlined
call to
‘std::allocator_traits<std::allocator<std::__detail::_Hash_node<std::pair<const
int, int>, false> > >::allocate’ from
‘std::__detail::_Hashtable_alloc<std::allocator<std::__detail::_Hash_node<std::pair<const
int, int>, false> > >::_M_allocate_node<const std::piecewise_construct_t&,
std::tuple<int&&>, std::tuple<> >’
│
└──> ‘static constexpr _Tp* std::allocator_traits<std::allocator<_Up>
>::allocate(allocator_type&, size_type) [with _Tp =
std::__detail::_Hash_node<std::pair<const int, int>, false>]’: event 3
│
│/opt/gcc-15/include/c++/15.2.0/bits/alloc_traits.h:614:28:
│ 614 | { return __a.allocate(__n); }
│ | ^
│ | |
│ | (3) inlined call to
‘std::allocator<std::__detail::_Hash_node<std::pair<const int, int>, false>
>::allocate’ from
‘std::allocator_traits<std::allocator<std::__detail::_Hash_node<std::pair<const
int, int>, false> > >::allocate’
│
└──> ‘constexpr _Tp* std::allocator< <template-parameter-1-1>
>::allocate(std::size_t) [with _Tp = std::__detail::_Hash_node<std::pair<const
int, int>, false>]’: events 4-5
│
│/opt/gcc-15/include/c++/15.2.0/bits/allocator.h:196:9:
│ 196 | if (std::__is_constant_evaluated())
│ | ^~
│ | |
│ | (4) following ‘false’ branch... ─>─┐
│ | │
│......
│ | │
│ |┌───────────────────────────────────────────┘
│ 203 |│ return __allocator_base<_Tp>::allocate(__n,
0);
│ |│
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
│ |│ |
│ |└─────────────────────────────────────────────>(5)
...to here
│
<─────────────┘
│
‘_Tp* std::__new_allocator<_Tp>::allocate(size_type, const void*) [with _Tp =
std::__detail::_Hash_node<std::pair<const int, int>, false>]’: event 6
│
│/opt/gcc-15/include/c++/15.2.0/bits/new_allocator.h:134:53:
│ 134 | if (__builtin_expect(__n > this->_M_max_size(), false))
│ | ^
│ | |
│ | (6) inlined
call to ‘std::__new_allocator<std::__detail::_Hash_node<std::pair<const int,
int>, false> >::_M_max_size’ from
‘std::__new_allocator<std::__detail::_Hash_node<std::pair<const int, int>,
false> >::allocate’
│
└──> ‘constexpr std::__new_allocator<_Tp>::size_type
std::__new_allocator<_Tp>::_M_max_size() const [with _Tp =
std::__detail::_Hash_node<std::pair<const int, int>, false>]’: event 7
│
│ 233 | return std::size_t(__PTRDIFF_MAX__) / sizeof(_Tp);
│ | ^
│ | |
│ | (7)
⚠️ ‘__a->std::__new_allocator<std::__detail::_Hash_node<std::pair<const int,
int>, false> >::allocate(__n, 0)’ leaks here
│
In member function ‘constexpr std::__new_allocator<_Tp>::size_type
std::__new_allocator<_Tp>::_M_max_size() const [with _Tp =
std::__detail::_Hash_node_base*]’,
inlined from ‘_Tp* std::__new_allocator<_Tp>::allocate(size_type, const
void*) [with _Tp = std::__detail::_Hash_node_base*]’ at
/opt/gcc-15/include/c++/15.2.0/bits/new_allocator.h:134:46:
/opt/gcc-15/include/c++/15.2.0/bits/new_allocator.h:233:57: warning: leak of
‘__alloc.std::__new_allocator<std::__detail::_Hash_node_base*>::allocate(__n,
0)’ [CWE-401] [-Wanalyzer-malloc-leak]
233 | return std::size_t(__PTRDIFF_MAX__) / sizeof(_Tp);
| ^
‘std::__detail::_Hashtable_alloc<_NodeAlloc>::__node_base**
std::__detail::_Hashtable_alloc<_NodeAlloc>::_M_allocate_buckets(std::size_t)
[with _NodeAlloc = std::allocator<std::__detail::_Hash_node<std::pair<const
int, int>, false> >]’: events 1-2
│
│/opt/gcc-15/include/c++/15.2.0/bits/hashtable_policy.h:1600:5:
│ 1600 | _Hashtable_alloc<_NodeAlloc>::_M_allocate_buckets(size_t
__bkt_count)
│ | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~
│ | |
│ | (1) entry to
‘std::__detail::_Hashtable_alloc<std::allocator<std::__detail::_Hash_node<std::pair<const
int, int>, false> > >::_M_allocate_buckets’
│......
│ 1605 | auto __ptr = __buckets_alloc_traits::allocate(__alloc,
__bkt_count);
│ | ~
│ | |
│ | (2) inlined
call to ‘std::allocator_traits<std::allocator<std::__detail::_Hash_node_base*>
>::allocate’ from
‘std::__detail::_Hashtable_alloc<std::allocator<std::__detail::_Hash_node<std::pair<const
int, int>, false> > >::_M_allocate_buckets’
│
└──> ‘static constexpr _Tp* std::allocator_traits<std::allocator<_Up>
>::allocate(allocator_type&, size_type) [with _Tp =
std::__detail::_Hash_node_base*]’: event 3
│
│/opt/gcc-15/include/c++/15.2.0/bits/alloc_traits.h:614:28:
│ 614 | { return __a.allocate(__n); }
│ | ^
│ | |
│ | (3) inlined call to
‘std::allocator<std::__detail::_Hash_node_base*>::allocate’ from
‘std::allocator_traits<std::allocator<std::__detail::_Hash_node_base*>
>::allocate’
│
└──> ‘constexpr _Tp* std::allocator< <template-parameter-1-1>
>::allocate(std::size_t) [with _Tp = std::__detail::_Hash_node_base*]’: events
4-5
│
│/opt/gcc-15/include/c++/15.2.0/bits/allocator.h:196:9:
│ 196 | if (std::__is_constant_evaluated())
│ | ^~
│ | |
│ | (4) following ‘false’ branch... ─>─┐
│ | │
│......
│ | │
│ |┌───────────────────────────────────────────┘
│ 203 |│ return __allocator_base<_Tp>::allocate(__n,
0);
│ |│
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
│ |│ |
│ |└─────────────────────────────────────────────>(5)
...to here
│
<─────────────┘
│
‘_Tp* std::__new_allocator<_Tp>::allocate(size_type, const void*) [with _Tp =
std::__detail::_Hash_node_base*]’: event 6
│
│/opt/gcc-15/include/c++/15.2.0/bits/new_allocator.h:134:53:
│ 134 | if (__builtin_expect(__n > this->_M_max_size(), false))
│ | ^
│ | |
│ | (6) inlined
call to ‘std::__new_allocator<std::__detail::_Hash_node_base*>::_M_max_size’
from ‘std::__new_allocator<std::__detail::_Hash_node_base*>::allocate’
│
└──> ‘constexpr std::__new_allocator<_Tp>::size_type
std::__new_allocator<_Tp>::_M_max_size() const [with _Tp =
std::__detail::_Hash_node_base*’: event 7
│
│ 233 | return std::size_t(__PTRDIFF_MAX__) / sizeof(_Tp);
│ | ^
│ | |
│ | (7)
⚠️
‘__alloc.std::__new_allocator<std::__detail::_Hash_node_base*>::allocate(__n,
0)’ leaks here
│