commit bdb028b38ace766538150d5ef7874123d0689cd7 Author: Jonathan Wakely Date: Wed May 31 11:40:14 2017 +0100 PR libstdc++/80893 Fix null dereference in vector PR libstdc++/80893 * include/bits/stl_bvector.h (vector::_M_initialize): Avoid null pointer dereference when size is zero. * testsuite/23_containers/vector/bool/80893.cc: New. * testsuite/util/testsuite_allocator.h (PointerBase::PointerBase): Add non-explicit constructor from nullptr. (PointerBase::derived() const): Add const-qualified overload. diff --git a/libstdc++-v3/include/bits/stl_bvector.h b/libstdc++-v3/include/bits/stl_bvector.h index 37e000a..78195c1 100644 --- a/libstdc++-v3/include/bits/stl_bvector.h +++ b/libstdc++-v3/include/bits/stl_bvector.h @@ -1089,9 +1089,17 @@ template void _M_initialize(size_type __n) { - _Bit_pointer __q = this->_M_allocate(__n); - this->_M_impl._M_end_of_storage = __q + _S_nword(__n); - this->_M_impl._M_start = iterator(std::__addressof(*__q), 0); + if (__n) + { + _Bit_pointer __q = this->_M_allocate(__n); + this->_M_impl._M_end_of_storage = __q + _S_nword(__n); + this->_M_impl._M_start = iterator(std::__addressof(*__q), 0); + } + else + { + this->_M_impl._M_end_of_storage = _Bit_pointer(); + this->_M_impl._M_start = iterator(0, 0); + } this->_M_impl._M_finish = this->_M_impl._M_start + difference_type(__n); } diff --git a/libstdc++-v3/testsuite/23_containers/vector/bool/80893.cc b/libstdc++-v3/testsuite/23_containers/vector/bool/80893.cc new file mode 100644 index 0000000..0545b38 --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/vector/bool/80893.cc @@ -0,0 +1,74 @@ +// Copyright (C) 2017 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// . + +// libstdc++/80893 + +#include +#include + +struct DereferencedInvalidPointer { }; + +// User-defined pointer type that throws if a null pointer is dereferenced. +template +struct Pointer : __gnu_test::PointerBase, T> +{ + using __gnu_test::PointerBase, T>::PointerBase; + + T& operator*() const + { + if (!this->value) + throw DereferencedInvalidPointer(); + return *this->value; + } +}; + +// Minimal allocator using Pointer +template +struct Alloc +{ + typedef T value_type; + typedef Pointer pointer; + + Alloc() = default; + template + Alloc(const Alloc&) { } + + pointer allocate(std::size_t n) + { + if (n) + return pointer(std::allocator().allocate(n)); + return nullptr; + } + + void deallocate(pointer p, std::size_t n) + { + if (n) + std::allocator().deallocate(p.value, n); + } +}; + +template +bool operator==(Alloc, Alloc) { return true; } + +template +bool operator!=(Alloc, Alloc) { return false; } + +int main() +{ + std::vector> v(0); + std::vector> w(v); +} diff --git a/libstdc++-v3/testsuite/util/testsuite_allocator.h b/libstdc++-v3/testsuite/util/testsuite_allocator.h index 813fc81..56c2708 100644 --- a/libstdc++-v3/testsuite/util/testsuite_allocator.h +++ b/libstdc++-v3/testsuite/util/testsuite_allocator.h @@ -570,6 +570,8 @@ namespace __gnu_test explicit PointerBase(T* p = nullptr) : value(p) { } + PointerBase(std::nullptr_t) : value(nullptr) { } + template(std::declval()))> PointerBase(const PointerBase& p) : value(p.value) { } @@ -603,7 +605,11 @@ namespace __gnu_test } private: - Derived& derived() { return static_cast(*this); } + Derived& + derived() { return static_cast(*this); } + + const Derived& + derived() const { return static_cast(*this); } }; template