]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
PR libstdc++/68197 fail on negative iword/pword indices
authorJonathan Wakely <jwakely@redhat.com>
Wed, 2 May 2018 19:04:55 +0000 (20:04 +0100)
committerJonathan Wakely <redi@gcc.gnu.org>
Wed, 2 May 2018 19:04:55 +0000 (20:04 +0100)
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

libstdc++-v3/ChangeLog
libstdc++-v3/include/bits/ios_base.h
libstdc++-v3/src/c++11/ios.cc
libstdc++-v3/testsuite/27_io/ios_base/storage/68197.cc [new file with mode: 0644]

index 7b17bd2f8b43782c62744791d75b99b634209f55..b251187813fe1b80a93d86cafb0c21a0c6b1f3dc 100644 (file)
@@ -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
index d296be4eb307d5ce93f662e1e90a8d683f669f93..c0c4e3b2abe3c9d6ca86f70670705f7abd38b24b 100644 (file)
@@ -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;
     }
index 82063e4b2f5db63064190c0b8cf812dc8f121d4a..f5351777f90de3949284353d8196cddb96d853dc 100644 (file)
@@ -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;
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 (file)
index 0000000..1004e81
--- /dev/null
@@ -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();
+}