https://gcc.gnu.org/bugzilla/show_bug.cgi?id=120466
Bug ID: 120466 Summary: Analyzer report for C++ 'std::stringbuf' instantiation Product: gcc Version: 16.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: analyzer Assignee: dmalcolm at gcc dot gnu.org Reporter: tschwinge at gcc dot gnu.org Target Milestone: --- Given: #include <sstream> void f() { std::stringbuf out_b; } ..., '-fanalyzer' reports: In file included from [...]/build-gcc/x86_64-pc-linux-gnu/libstdc++-v3/include/x86_64-pc-linux-gnu/bits/c++allocator.h:33, from [...]/build-gcc/x86_64-pc-linux-gnu/libstdc++-v3/include/bits/allocator.h:46, from [...]/build-gcc/x86_64-pc-linux-gnu/libstdc++-v3/include/string:45, from [...]/build-gcc/x86_64-pc-linux-gnu/libstdc++-v3/include/bits/locale_classes.h:42, from [...]/build-gcc/x86_64-pc-linux-gnu/libstdc++-v3/include/bits/ios_base.h:43, from [...]/build-gcc/x86_64-pc-linux-gnu/libstdc++-v3/include/ios:46, from [...]/build-gcc/x86_64-pc-linux-gnu/libstdc++-v3/include/istream:42, from [...]/build-gcc/x86_64-pc-linux-gnu/libstdc++-v3/include/sstream:42, from [...]/a.C:1: [...]/build-gcc/x86_64-pc-linux-gnu/libstdc++-v3/include/bits/new_allocator.h: In member function ‘void std::__new_allocator<_Tp>::deallocate(_Tp*, size_type) [with _Tp = char]’: [...]/build-gcc/x86_64-pc-linux-gnu/libstdc++-v3/include/bits/new_allocator.h:172:66: warning: ‘delete’ of ‘__p’ which points to memory on the stack [CWE-590] [-Wanalyzer-free-of-non-heap] 172 | _GLIBCXX_OPERATOR_DELETE(_GLIBCXX_SIZED_DEALLOC(__p, __n)); | ^ ‘void f()’: events 1-3 | |[...]/a.C:2:6: | 2 | void f() | | ^ | | | | | (1) entry to ‘f’ | 3 | { | 4 | std::stringbuf out_b; | | ~~~~~ | | | | | (2) region created on stack here | 5 | } | | ~ | | | | | (3) calling ‘std::__cxx11::basic_stringbuf<char>::~basic_stringbuf’ from ‘f’ | +--> ‘std::__cxx11::basic_stringbuf<char>::~basic_stringbuf()’: events 4-5 | |[...]/build-gcc/x86_64-pc-linux-gnu/libstdc++-v3/include/sstream:81:11: | 81 | class basic_stringbuf : public basic_streambuf<_CharT, _Traits> | | ^~~~~~~~~~~~~~~ | | | | | (4) entry to ‘std::__cxx11::basic_stringbuf<char>::~basic_stringbuf’ | | (5) calling ‘std::__cxx11::basic_string<char>::~basic_string’ from ‘std::__cxx11::basic_stringbuf<char>::~basic_stringbuf’ | +--> ‘constexpr std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::~basic_string() [with _CharT = char; _Traits = std::char_traits<char>; _Alloc = std::allocator<char>]’: events 6-7 | |[...]/build-gcc/x86_64-pc-linux-gnu/libstdc++-v3/include/bits/basic_string.h:895:7: | 895 | ~basic_string() | | ^ | | | | | (6) entry to ‘std::__cxx11::basic_string<char>::~basic_string’ | 896 | { _M_dispose(); } | | ~~~~~~~~~~~~ | | | | | (7) calling ‘std::__cxx11::basic_string<char>::_M_dispose’ from ‘std::__cxx11::basic_string<char>::~basic_string’ | +--> ‘constexpr void std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::_M_dispose() [with _CharT = char; _Traits = std::char_traits<char>; _Alloc = std::allocator<char>]’: events 8-9 | | 296 | _M_dispose() | | ^~~~~~~~~~ | | | | | (8) entry to ‘std::__cxx11::basic_string<char>::_M_dispose’ | 297 | { | 298 | if (!_M_is_local()) | | ~~~~~~~~~~~~~ | | | | | (9) calling ‘std::__cxx11::basic_string<char>::_M_is_local’ from ‘std::__cxx11::basic_string<char>::_M_dispose’ | +--> ‘constexpr bool std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::_M_is_local() const [with _CharT = char; _Traits = std::char_traits<char>; _Alloc = std::allocator<char>]’: events 10-12 | | 278 | _M_is_local() const | | ^~~~~~~~~~~ | | | | | (10) entry to ‘std::__cxx11::basic_string<char>::_M_is_local’ | 279 | { | 280 | if (_M_data() == _M_local_data()) | | ~~ | | | | | (11) following ‘false’ branch... ->-+ | | | |...... | | | | |+--------------------------------------------+ | 286 || return false; | || ~~~~~ | || | | |+-------------->(12) ...to here | <------+ | ‘constexpr void std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::_M_dispose() [with _CharT = char; _Traits = std::char_traits<char>; _Alloc = std::allocator<char>]’: event 13 | | 298 | if (!_M_is_local()) | | ~~~~~~~~~~~^~ | | | | | (13) returning to ‘std::__cxx11::basic_string<char>::_M_dispose’ from ‘std::__cxx11::basic_string<char>::_M_is_local’ | ‘constexpr void std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::_M_dispose() [with _CharT = char; _Traits = std::char_traits<char>; _Alloc = std::allocator<char>]’: events 14-16 | | 298 | if (!_M_is_local()) | | ^~ | | | | | (14) following ‘true’ branch... ->-+ | | | | | | | |+-------------------------------------------+ | 299 || _M_destroy(_M_allocated_capacity); | || ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | || | | |+------------------->(15) ...to here | | (16) calling ‘std::__cxx11::basic_string<char>::_M_destroy’ from ‘std::__cxx11::basic_string<char>::_M_dispose’ | +--> ‘constexpr void std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::_M_destroy(size_type) [with _CharT = char; _Traits = std::char_traits<char>; _Alloc = std::allocator<char>]’: events 17-18 | | 304 | _M_destroy(size_type __size) throw() | | ^~~~~~~~~~ | | | | | (17) entry to ‘std::__cxx11::basic_string<char>::_M_destroy’ | 305 | { _Alloc_traits::deallocate(_M_get_allocator(), _M_data(), __size + 1); } | | ~ | | | | | (18) inlined call to ‘std::allocator_traits<std::allocator<char> >::deallocate’ from ‘std::__cxx11::basic_string<char>::_M_destroy’ | +--> ‘static constexpr void std::allocator_traits<std::allocator<_CharT> >::deallocate(allocator_type&, pointer, size_type) [with _Tp = char]’: event 19 | |[...]/build-gcc/x86_64-pc-linux-gnu/libstdc++-v3/include/bits/alloc_traits.h:649:23: | 649 | { __a.deallocate(__p, __n); } | | ^ | | | | | (19) inlined call to ‘std::allocator<char>::deallocate’ from ‘std::allocator_traits<std::allocator<char> >::deallocate’ | +--> ‘constexpr void std::allocator< <template-parameter-1-1> >::deallocate(_Tp*, std::size_t) [with _Tp = char]’: event 20 | |[...]/build-gcc/x86_64-pc-linux-gnu/libstdc++-v3/include/bits/allocator.h:215:42: | 215 | __allocator_base<_Tp>::deallocate(__p, __n); | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~ | | | | | (20) calling ‘std::__new_allocator<char>::deallocate’ from ‘std::__cxx11::basic_string<char>::_M_destroy’ | <------+ | ‘void std::__new_allocator<_Tp>::deallocate(_Tp*, size_type) [with _Tp = char]’: events 21-22 | |[...]/build-gcc/x86_64-pc-linux-gnu/libstdc++-v3/include/bits/new_allocator.h:156:7: | 156 | deallocate(_Tp* __p, size_type __n __attribute__ ((__unused__))) | | ^~~~~~~~~~ | | | | | (21) entry to ‘std::__new_allocator<char>::deallocate’ |...... | 172 | _GLIBCXX_OPERATOR_DELETE(_GLIBCXX_SIZED_DEALLOC(__p, __n)); | | ~ | | | | | (22) call to ‘delete’ here | Is that a false positive to be fixed in the analyzer (perhaps just C++ idioms not supported yet), or is there an actual in the libstdc++ code?