Bug 108860 - [12/13 regression] New (since gcc 12) false positive null-dereference in vector.resize
Summary: [12/13 regression] New (since gcc 12) false positive null-dereference in vect...
Status: NEW
Alias: None
Product: gcc
Classification: Unclassified
Component: tree-optimization (show other bugs)
Version: 12.2.0
: P2 normal
Target Milestone: 12.5
Assignee: Not yet assigned to anyone
URL:
Keywords: diagnostic, needs-bisection
Depends on:
Blocks: Wnull-dereference
  Show dependency treegraph
 
Reported: 2023-02-20 12:49 UTC by Demian Hespe
Modified: 2025-02-09 02:17 UTC (History)
1 user (show)

See Also:
Host:
Target:
Build:
Known to work: 14.2.1, 15.0
Known to fail: 12.4.1, 13.2.1
Last reconfirmed: 2023-02-21 00:00:00


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Demian Hespe 2023-02-20 12:49:38 UTC
The following code produces a warning with gcc 12.1 (tested with godbolt) and 12.2 (tested with godbolt and the version on ubuntu 22.10), but not with gcc 11.3 (tested with godbolt):

❯ cat test.cpp
#include <vector>

void test(std::size_t val1, std::size_t val2) {
    std::vector<int> data;
    if(val2 > 0)
        data.resize(val1 / val2);
}
❯ g++ -O2 -Wnull-dereference test.cpp
In file included from /usr/include/c++/12/vector:62,
                 from test.cpp:1:
In function ‘void std::_Construct(_Tp*, _Args&& ...) [with _Tp = int; _Args = {}]’,
    inlined from ‘static _ForwardIterator std::__uninitialized_default_n_1<true>::__uninit_default_n(_ForwardIterator, _Size) [with _ForwardIterator = int*; _Size = long unsigned int]’ at /usr/include/c++/12/bits/stl_uninitialized.h:661:23,
    inlined from ‘static _ForwardIterator std::__uninitialized_default_n_1<true>::__uninit_default_n(_ForwardIterator, _Size) [with _ForwardIterator = int*; _Size = long unsigned int]’ at /usr/include/c++/12/bits/stl_uninitialized.h:655:9,
    inlined from ‘_ForwardIterator std::__uninitialized_default_n(_ForwardIterator, _Size) [with _ForwardIterator = int*; _Size = long unsigned int]’ at /usr/include/c++/12/bits/stl_uninitialized.h:701:20,
    inlined from ‘_ForwardIterator std::__uninitialized_default_n_a(_ForwardIterator, _Size, allocator<_Tp>&) [with _ForwardIterator = int*; _Size = long unsigned int; _Tp = int]’ at /usr/include/c++/12/bits/stl_uninitialized.h:766:44,
    inlined from ‘void std::vector<_Tp, _Alloc>::_M_default_append(size_type) [with _Tp = int; _Alloc = std::allocator<int>]’ at /usr/include/c++/12/bits/vector.tcc:655:41,
    inlined from ‘void std::vector<_Tp, _Alloc>::resize(size_type) [with _Tp = int; _Alloc = std::allocator<int>]’ at /usr/include/c++/12/bits/stl_vector.h:1011:21,
    inlined from ‘void test(std::size_t, std::size_t)’ at test.cpp:6:20:
/usr/include/c++/12/bits/stl_construct.h:119:7: warning: null pointer dereference [-Wnull-dereference]
  119 |       ::new((void*)__p) _Tp(std::forward<_Args>(__args)...);
      |       ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~


The `if(val2 > 0)` is not necessary to produce the warning but I wanted to make sure that this isn't due to a possible division by zero. 
The warning is also output with -O3 but not with -O1 or -O0.
Comment 1 Jonathan Wakely 2023-02-21 01:46:29 UTC
Somehow GCC thinks __len can be 0 here, and so __new_start can be null:

	      const size_type __len =
		_M_check_len(__n, "vector::_M_default_append");
	      pointer __new_start(this->_M_allocate(__len));
Comment 2 Sam James 2024-06-15 02:10:41 UTC
10/11 are fine
Comment 3 Alexandre Duret-Lutz 2024-06-27 13:29:12 UTC
Arrived here because I have the same issue, but with an even simpler input.


% cat foo.c 
#include <vector>

void test(std::vector<int>& v)
{
  v.insert(v.begin(), 12);
}
% g++ -O -std=c++20 -Werror=null-dereference -c  foo.cc
In file included from /usr/include/c++/13/bits/stl_iterator.h:85,
                 from /usr/include/c++/13/bits/stl_algobase.h:67,
                 from /usr/include/c++/13/vector:62,
                 from foo.cc:1:
In function ‘constexpr decltype (::new(void*(0)) _Tp) std::construct_at(_Tp*, _Args&& ...) [with _Tp = int; _Args = {int}]’,
    inlined from ‘static constexpr void std::allocator_traits<std::allocator<_Up> >::construct(allocator_type&, _Up*, _Args&& ...) [with _Up = int; _Args = {int}; _Tp = int]’ at /usr/include/c++/13/bits/alloc_traits.h:540:21,
    inlined from ‘constexpr void std::vector<_Tp, _Alloc>::_M_realloc_insert(iterator, _Args&& ...) [with _Args = {int}; _Tp = int; _Alloc = std::allocator<int>]’ at /usr/include/c++/13/bits/vector.tcc:468:28,
    inlined from ‘constexpr std::vector<_Tp, _Alloc>::iterator std::vector<_Tp, _Alloc>::_M_insert_rval(const_iterator, value_type&&) [with _Tp = int; _Alloc = std::allocator<int>]’ at /usr/include/c++/13/bits/vector.tcc:372:19,
    inlined from ‘constexpr std::vector<_Tp, _Alloc>::iterator std::vector<_Tp, _Alloc>::insert(const_iterator, value_type&&) [with _Tp = int; _Alloc = std::allocator<int>]’ at /usr/include/c++/13/bits/stl_vector.h:1394:30,
    inlined from ‘void test(std::vector<int>&)’ at foo.cc:5:11:
/usr/include/c++/13/bits/stl_construct.h:97:14: error: potential null pointer dereference [-Werror=null-dereference]
   97 |     { return ::new((void*)__location) _Tp(std::forward<_Args>(__args)...); }
      |              ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
cc1plus: some warnings being treated as errors


Reproduced with 
- g++-13 (Debian 13.2.0-25) 13.2.0
- g++-12 (Debian 12.3.0-17) 12.3.0
Comment 4 Sam James 2025-02-09 02:17:47 UTC
14/15 owrks.