mirror of
https://gcc.gnu.org/git/gcc.git
synced 2025-01-02 00:43:44 +08:00
PR libstdc++/68197 fail on negative iword/pword indices
The suggested resolution of LWG 3083 is to make invalid indices undefined, but we can fairly easily check for them and treat them as errors in the same way as allocation failure. This avoids a segfault or worse, setting an error flag on the stream instead. 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. From-SVN: r259854
This commit is contained in:
parent
006fbbe952
commit
85d0fad469
@ -1,5 +1,12 @@
|
||||
2018-05-02 Jonathan Wakely <jwakely@redhat.com>
|
||||
|
||||
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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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<int>::max())
|
||||
__error = __N("ios_base::_M_grow_words is not valid");
|
||||
else if (__ix > _S_local_word_size - 1)
|
||||
{
|
||||
if (__ix < numeric_limits<int>::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;
|
||||
|
95
libstdc++-v3/testsuite/27_io/ios_base/storage/68197.cc
Normal file
95
libstdc++-v3/testsuite/27_io/ios_base/storage/68197.cc
Normal file
@ -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
|
||||
// <http://www.gnu.org/licenses/>.
|
||||
|
||||
// { dg-do run { target c++11 } }
|
||||
|
||||
#include <ios>
|
||||
#include <climits>
|
||||
#include <testsuite_hooks.h>
|
||||
|
||||
// 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();
|
||||
}
|
Loading…
Reference in New Issue
Block a user