public inbox for gcc-bugs@sourceware.org
help / color / mirror / Atom feed
* [Bug libstdc++/110542] New: use of allocated storage after deallocation in a constant expression: std::array of std::vector<bool>
@ 2023-07-04 12:45 hal.finkel.oss at gmail dot com
  2023-07-04 14:26 ` [Bug libstdc++/110542] use of allocated storage after deallocation in a constant expression: std::array of std::vector<int> redi at gcc dot gnu.org
                   ` (10 more replies)
  0 siblings, 11 replies; 12+ messages in thread
From: hal.finkel.oss at gmail dot com @ 2023-07-04 12:45 UTC (permalink / raw)
  To: gcc-bugs

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=110542

            Bug ID: 110542
           Summary: use of allocated storage after deallocation in a
                    constant expression: std::array of std::vector<bool>
           Product: gcc
           Version: 13.1.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: libstdc++
          Assignee: unassigned at gcc dot gnu.org
          Reporter: hal.finkel.oss at gmail dot com
  Target Milestone: ---

For this test case:

```
#include <vector>
#include <array>

struct s_t {
  std::vector<std::array<std::vector<int>, 1>> v;

  constexpr void rz(std::size_t n) {
    v.resize(n);
    for (auto &x : v) for (auto &w : x) w.resize(n);
  }
};

constexpr std::size_t test1() {
  s_t s;
  s.rz(1);
  s.rz(2);
  return 1;
}

int main() {
  static_assert(test1() == 1);
}
```

g++ -std=c++20 13.1.0 (and GCC trunk as of today on https://gcc.godbolt.org/):
ERROR:

```
tc1.cpp: In function ‘int main()’:
tc1.cpp:21:25: error: non-constant condition for static assertion
   21 |   static_assert(test1() == 1);
      |                 ~~~~~~~~^~~~
tc1.cpp:21:22:   in ‘constexpr’ expansion of ‘test1()’
tc1.cpp:16:7:   in ‘constexpr’ expansion of ‘s.s_t::rz(2)’
tc1.cpp:9:49:   in ‘constexpr’ expansion of ‘(&
w)->std::vector<int>::resize(n)’
/gcc-13.1.0/include/c++/13/bits/stl_vector.h:1011:21:   in ‘constexpr’
expansion of
‘((std::vector<int>*)this)->std::vector<int>::_M_default_append((__new_size -
((std::vector<int>*)this)->std::vector<int>::size()))’
/gcc-13.1.0/include/c++/13/bits/vector.tcc:676:16:   in ‘constexpr’ expansion
of ‘std::vector<int>::_S_relocate(__old_start, __old_finish, __new_start, (*
&((std::vector<int>*)this)->std::vector<int>::<anonymous>.std::_Vector_base<int,
std::allocator<int> >::_M_get_Tp_allocator()))’
/gcc-13.1.0/include/c++/13/bits/stl_vector.h:504:26:   in ‘constexpr’ expansion
of ‘std::__relocate_a<int*, int*, allocator<int> >(__first, __last, __result,
(* & __alloc))’
/gcc-13.1.0/include/c++/13/bits/stl_uninitialized.h:1142:33:   in ‘constexpr’
expansion of ‘std::__relocate_a_1<int, int>(std::__niter_base<int*>(__first),
std::__niter_base<int*>(__last), std::__niter_base<int*>(__result), (* &
__alloc))’
/gcc-13.1.0/include/c++/13/bits/stl_uninitialized.h:1122:35:   in ‘constexpr’
expansion of ‘std::__relocate_a_1<int*, __gnu_cxx::__normal_iterator<int*,
void>, allocator<int> >(__first, __last, __out, (* & __alloc))’
/gcc-13.1.0/include/c++/13/bits/stl_uninitialized.h:1100:26:   in ‘constexpr’
expansion of ‘std::__relocate_object_a<int, int, allocator<int>
>(std::__addressof<int>((* & __cur.__gnu_cxx::__normal_iterator<int*,
void>::operator*())), std::__addressof<int>((* __first)), (* & __alloc))’
/gcc-13.1.0/include/c++/13/bits/stl_uninitialized.h:1072:26:   in ‘constexpr’
expansion of ‘std::allocator_traits<std::allocator<int> >::construct<int,
int>((* & __alloc), __dest, (* & std::move<int&>((*(int*)__orig))))’
/gcc-13.1.0/include/c++/13/bits/alloc_traits.h:539:21:   in ‘constexpr’
expansion of ‘std::construct_at<int, int>(__p, (* & std::forward<int>((* &
__args#0))))’
tc1.cpp:21:25: error: use of allocated storage after deallocation in a constant
expression
In file included from /gcc-13.1.0/include/c++/13/vector:63,
                 from tc1.cpp:1:
/gcc-13.1.0/include/c++/13/bits/allocator.h:195:52: note: allocated here
  195 |             return static_cast<_Tp*>(::operator new(__n));
      |                                      ~~~~~~~~~~~~~~^~~~~

```

clang -std=c++20 15, (and 16 and trunk as of today on https://gcc.godbolt.org/,
noting that these appear to use headers from libstdc++ gcc-12.2.0; below is
from clang 15 using GCC 13.1.0 headers): ERROR:

```
tc1.cpp:21:17: error: static assertion expression is not an integral constant
expression
  static_assert(test1() == 1);
                ^~~~~~~~~~~~
/gcc-13.1.0/lib/gcc/x86_64-redhat-linux/13/../../../../include/c++/13/bits/stl_algobase.h:931:11:
note: assignment to object outside its lifetime is not allowed in a constant
expression
        *__first = __tmp;
                 ^
/gcc-13.1.0/lib/gcc/x86_64-redhat-linux/13/../../../../include/c++/13/bits/stl_algobase.h:977:7:
note: in call to '__fill_a1(&{*new int[2]#4}[1], &{*new int[2]#4}[2], {*new
int[2]#4}[0])'
    { std::__fill_a1(__first, __last, __value); }
      ^
/gcc-13.1.0/lib/gcc/x86_64-redhat-linux/13/../../../../include/c++/13/bits/stl_algobase.h:1128:7:
note: in call to '__fill_a(&{*new int[2]#4}[1], &{*new int[2]#4}[2], {*new
int[2]#4}[0])'
      std::__fill_a(__first, __first + __n, __value);
      ^
/gcc-13.1.0/lib/gcc/x86_64-redhat-linux/13/../../../../include/c++/13/bits/stl_algobase.h:1157:14:
note: in call to '__fill_n_a(&{*new int[2]#4}[1], 1, {*new int[2]#4}[0],
{{{{}}}})'
      return std::__fill_n_a(__first, std::__size_to_integer(__n), __value,
             ^
/gcc-13.1.0/lib/gcc/x86_64-redhat-linux/13/../../../../include/c++/13/bits/stl_uninitialized.h:668:18:
note: in call to 'fill_n(&{*new int[2]#4}[1], 1, {*new int[2]#4}[0])'
              __first = std::fill_n(__first, __n - 1, *__val);
                        ^
/gcc-13.1.0/lib/gcc/x86_64-redhat-linux/13/../../../../include/c++/13/bits/stl_uninitialized.h:704:14:
note: in call to '__uninit_default_n(&{*new int[2]#4}[1], 2)'
      return __uninitialized_default_n_1<__is_trivial(_ValueType)
             ^
/gcc-13.1.0/lib/gcc/x86_64-redhat-linux/13/../../../../include/c++/13/bits/stl_uninitialized.h:773:14:
note: (skipping 1 call in backtrace; use -fconstexpr-backtrace-limit=0 to see
all)
    { return std::__uninitialized_default_n(__first, __n); }
             ^
/gcc-13.1.0/lib/gcc/x86_64-redhat-linux/13/../../../../include/c++/13/bits/vector.tcc:668:9:
note: in call to '__uninitialized_default_n_a(&{*new int[2]#4}[0], 2, {*new
std::array<std::vector<int>, 1>[2]#2}[1]._M_elems[0]._Vector_base::_M_impl)'
                      std::__uninitialized_default_n_a(__new_start + __size,
                      ^
/gcc-13.1.0/lib/gcc/x86_64-redhat-linux/13/../../../../include/c++/13/bits/stl_vector.h:1011:4:
note: in call to '&{*new std::array<std::vector<int>,
1>[2]#2}[1]._M_elems[0]->_M_default_append(2)'
          _M_default_append(__new_size - size());
          ^
tc1.cpp:9:43: note: in call to '&{*new std::array<std::vector<int>,
1>[2]#2}[1]._M_elems[0]->resize(2)'
    for (auto &x : v) for (auto &w : x) w.resize(n);
                                          ^
tc1.cpp:16:5: note: in call to '&s->rz(2)'
  s.rz(2);
    ^
tc1.cpp:21:17: note: in call to 'test1()'
  static_assert(test1() == 1);
                ^
1 error generated.

```

clang -std=c++20 -stdlib=libc++ 15, 16, and trunk as of today on
https://gcc.godbolt.org/): OK

I realize that this might be two compiler bugs, and I see, e.g., GCC bug
101777, but the fact that both GCC and clang provide what seem like they might
be the same semantic error, a use after deallocation, albeit pointing at
slightly different places in the libstdc++ headers, both on the second resize,
and it works with libc++, is why I suspect that it might be an issue in the
library (and the error message here is different from the one in 101777). Or,
of course, my code has UB and the compilers are correct.

^ permalink raw reply	[flat|nested] 12+ messages in thread

end of thread, other threads:[~2024-06-11 17:06 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-07-04 12:45 [Bug libstdc++/110542] New: use of allocated storage after deallocation in a constant expression: std::array of std::vector<bool> hal.finkel.oss at gmail dot com
2023-07-04 14:26 ` [Bug libstdc++/110542] use of allocated storage after deallocation in a constant expression: std::array of std::vector<int> redi at gcc dot gnu.org
2023-07-04 14:31 ` redi at gcc dot gnu.org
2023-07-04 14:35 ` redi at gcc dot gnu.org
2023-07-04 14:53 ` redi at gcc dot gnu.org
2023-07-04 14:56 ` redi at gcc dot gnu.org
2023-07-05  6:39 ` cvs-commit at gcc dot gnu.org
2023-07-05 11:24 ` redi at gcc dot gnu.org
2023-07-05 12:39 ` redi at gcc dot gnu.org
2023-07-05 17:37 ` redi at gcc dot gnu.org
2023-07-18 11:01 ` cvs-commit at gcc dot gnu.org
2024-06-11 17:06 ` cvs-commit at gcc dot gnu.org

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).