diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog index 7b17bd2f8b4..b251187813f 100644 --- a/libstdc++-v3/ChangeLog +++ b/libstdc++-v3/ChangeLog @@ -1,5 +1,12 @@ 2018-05-02 Jonathan Wakely + PR libstdc++/68197 + * include/bits/ios_base.h (ios_base::iword, ios_base::pword): Cast + indices to unsigned. + * src/c++11/ios.cc (ios_base::_M_grow_words): Treat negative indices + as failure. Refactor error handling. + * testsuite/27_io/ios_base/storage/68197.cc: New. + PR libstdc++/57997 PR libstdc++/83860 * include/bits/gslice_array.h (gslice_array): Define default diff --git a/libstdc++-v3/include/bits/ios_base.h b/libstdc++-v3/include/bits/ios_base.h index d296be4eb30..c0c4e3b2abe 100644 --- a/libstdc++-v3/include/bits/ios_base.h +++ b/libstdc++-v3/include/bits/ios_base.h @@ -810,7 +810,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION long& iword(int __ix) { - _Words& __word = (__ix < _M_word_size) + _Words& __word = ((unsigned)__ix < (unsigned)_M_word_size) ? _M_word[__ix] : _M_grow_words(__ix, true); return __word._M_iword; } @@ -831,7 +831,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION void*& pword(int __ix) { - _Words& __word = (__ix < _M_word_size) + _Words& __word = ((unsigned)__ix < (unsigned)_M_word_size) ? _M_word[__ix] : _M_grow_words(__ix, false); return __word._M_pword; } diff --git a/libstdc++-v3/src/c++11/ios.cc b/libstdc++-v3/src/c++11/ios.cc index 82063e4b2f5..f5351777f90 100644 --- a/libstdc++-v3/src/c++11/ios.cc +++ b/libstdc++-v3/src/c++11/ios.cc @@ -109,37 +109,30 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION ios_base::register_callback(event_callback __fn, int __index) { _M_callbacks = new _Callback_list(__fn, __index, _M_callbacks); } - // 27.4.2.5 iword/pword storage + // 27.4.2.5 [ios.base.storage] iword/pword storage ios_base::_Words& ios_base::_M_grow_words(int __ix, bool __iword) { // Precondition: _M_word_size <= __ix int __newsize = _S_local_word_size; _Words* __words = _M_local_word; - if (__ix > _S_local_word_size - 1) + const char* __error = nullptr; + if ((unsigned)__ix >= (unsigned)numeric_limits::max()) + __error = __N("ios_base::_M_grow_words is not valid"); + else if (__ix > _S_local_word_size - 1) { - if (__ix < numeric_limits::max()) + __newsize = __ix + 1; + /* We still need to catch bad_alloc even though we use + a nothrow new, because the new-expression can throw + a bad_array_new_length. */ + __try + { __words = new (std::nothrow) _Words[__newsize]; } + __catch(const std::bad_alloc&) + { __words = nullptr; } + if (!__words) + __error = __N("ios_base::_M_grow_words allocation failed"); + else { - __newsize = __ix + 1; - /* We still need to catch bad_alloc even though we use - a nothrow new, because the new-expression can throw - a bad_array_new_length. */ - __try - { __words = new (std::nothrow) _Words[__newsize]; } - __catch(const std::bad_alloc&) - { __words = nullptr; } - if (!__words) - { - _M_streambuf_state |= badbit; - if (_M_streambuf_state & _M_exception) - __throw_ios_failure(__N("ios_base::_M_grow_words " - "allocation failed")); - if (__iword) - _M_word_zero._M_iword = 0; - else - _M_word_zero._M_pword = 0; - return _M_word_zero; - } for (int __i = 0; __i < _M_word_size; __i++) __words[__i] = _M_word[__i]; if (_M_word && _M_word != _M_local_word) @@ -148,17 +141,17 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION _M_word = 0; } } + } + if (__error) + { + _M_streambuf_state |= badbit; + if (_M_streambuf_state & _M_exception) + __throw_ios_failure(__error); + if (__iword) + _M_word_zero._M_iword = 0; else - { - _M_streambuf_state |= badbit; - if (_M_streambuf_state & _M_exception) - __throw_ios_failure(__N("ios_base::_M_grow_words is not valid")); - if (__iword) - _M_word_zero._M_iword = 0; - else - _M_word_zero._M_pword = 0; - return _M_word_zero; - } + _M_word_zero._M_pword = 0; + return _M_word_zero; } _M_word = __words; _M_word_size = __newsize; diff --git a/libstdc++-v3/testsuite/27_io/ios_base/storage/68197.cc b/libstdc++-v3/testsuite/27_io/ios_base/storage/68197.cc new file mode 100644 index 00000000000..1004e8127c2 --- /dev/null +++ b/libstdc++-v3/testsuite/27_io/ios_base/storage/68197.cc @@ -0,0 +1,95 @@ +// Copyright (C) 2018 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 +// . + +// { dg-do run { target c++11 } } + +#include +#include +#include + +// PR libstdc++/68197 + +struct sbuf : std::streambuf { } sb; + +void +test01() +{ + std::ios ios(&sb); + long& i1 = ios.iword(-1); + VERIFY( i1 == 0 ); + VERIFY( ios.bad() ); + ios.clear(); + i1 = 1; + VERIFY( ios.iword(-1) == 0 ); + VERIFY( ios.bad() ); + ios.clear(); + long& i2 = ios.iword(INT_MIN); + VERIFY( i2 == 0 ); + VERIFY( ios.bad() ); + ios.clear(); + i2 = 2; + VERIFY( ios.iword(INT_MIN) == 0 ); + VERIFY( ios.bad() ); + ios.clear(); + + bool caught = false; + ios.exceptions(std::ios::badbit); + try { + ios.iword(-1); + } catch (const std::exception&) { + caught = true; + } + VERIFY( caught ); +} + +void +test02() +{ + std::ios ios(&sb); + void*& p1 = ios.pword(-1); + VERIFY( p1 == nullptr ); + VERIFY( ios.bad() ); + ios.clear(); + p1 = &p1; + VERIFY( ios.pword(-1) == nullptr ); + VERIFY( ios.bad() ); + ios.clear(); + void*& p2 = ios.pword(INT_MIN); + VERIFY( p2 == nullptr ); + VERIFY( ios.bad() ); + ios.clear(); + p2 = &p2; + VERIFY( ios.pword(INT_MIN) == nullptr ); + VERIFY( ios.bad() ); + ios.clear(); + + bool caught = false; + ios.exceptions(std::ios::badbit); + try { + ios.pword(-1); + } catch (const std::exception&) { + caught = true; + } + VERIFY( caught ); +} + +int +main() +{ + test01(); + test02(); +}