aboutsummaryrefslogtreecommitdiff
path: root/libstdc++-v3/testsuite/27_io/basic_istream
diff options
context:
space:
mode:
authorJonathan Wakely <jwakely@redhat.com>2020-07-20 20:06:46 +0100
committerJonathan Wakely <jwakely@redhat.com>2020-07-20 20:06:46 +0100
commit4d1c5b4957db2cb07f1053b7b87767275497d52e (patch)
tree177ba6f54bbfb42d2f020e0295ebf30ae0604107 /libstdc++-v3/testsuite/27_io/basic_istream
parent138b1d4f58af17986e856e665ffbd561c2c8740e (diff)
downloadgcc-4d1c5b4957db2cb07f1053b7b87767275497d52e.zip
gcc-4d1c5b4957db2cb07f1053b7b87767275497d52e.tar.gz
gcc-4d1c5b4957db2cb07f1053b7b87767275497d52e.tar.bz2
libstdc++: Avoid overflow in istream::get(streambuf&) [LWG 3464]
Similar to the recent changes to basic_istream::ignore, this change ensures that _M_gcount doesn't overflow when extracting characters and inserting them into another streambuf. The solution used here is to use unsigned long long for the count. We assume that the number of characters extracted won't exceed the maximum value for that type, but even if it does we avoid any undefined behaviour. libstdc++-v3/ChangeLog: * include/bits/istream.tcc (basic_istream::get(__streambuf_type&, char_type): Use unsigned long long for counter and check if it would overflow _M_gcount. * testsuite/27_io/basic_istream/get/char/lwg3464.cc: New test. * testsuite/27_io/basic_istream/get/wchar_t/lwg3464.cc: New test.
Diffstat (limited to 'libstdc++-v3/testsuite/27_io/basic_istream')
-rw-r--r--libstdc++-v3/testsuite/27_io/basic_istream/get/char/lwg3464.cc91
-rw-r--r--libstdc++-v3/testsuite/27_io/basic_istream/get/wchar_t/lwg3464.cc91
2 files changed, 182 insertions, 0 deletions
diff --git a/libstdc++-v3/testsuite/27_io/basic_istream/get/char/lwg3464.cc b/libstdc++-v3/testsuite/27_io/basic_istream/get/char/lwg3464.cc
new file mode 100644
index 0000000..6123ca5
--- /dev/null
+++ b/libstdc++-v3/testsuite/27_io/basic_istream/get/char/lwg3464.cc
@@ -0,0 +1,91 @@
+// Copyright (C) 2020 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 { ! lp64 } } }
+
+#include <istream>
+#include <streambuf>
+#include <limits>
+#include <testsuite_hooks.h>
+
+typedef char C;
+
+struct buff : std::basic_streambuf<C>
+{
+ typedef std::streamsize streamsize;
+ typedef std::numeric_limits<streamsize> limits;
+
+ buff() : count(0), buf() { }
+
+ int_type underflow()
+ {
+ // Number of characters left until we overflow the counter
+ const streamsize headroom = limits::max() - count;
+
+ if (headroom == 0)
+ return traits_type::eof();
+
+ if (bufsz < headroom)
+ count += bufsz;
+ else
+ count = limits::max();
+
+ this->setg(buf + 1, buf + 1, buf + bufsz);
+
+ return buf[0];
+ }
+
+ int_type overflow(int_type c)
+ {
+ if (traits_type::eq_int_type(c , traits_type::eof()))
+ return c;
+ this->setp(buf, buf + bufsz - 1);
+ return traits_type::not_eof(c);
+ }
+
+ streamsize count;
+
+ static const streamsize bufsz = (2048 << limits::digits10) + 1;
+ char_type buf[bufsz];
+};
+
+void
+test01()
+{
+ // Not possible to overflow 64-bit streamsize in reasonable time.
+ if (std::numeric_limits<std::streamsize>::digits > 32)
+ return;
+
+ std::basic_istream<C> in(new buff);
+ buff out;
+ in.get(out);
+ VERIFY( in.gcount() == std::numeric_limits<std::streamsize>::max() );
+
+ delete in.rdbuf(new buff);
+
+ in.get();
+ VERIFY( in.gcount() == 1 );
+
+ in.get(out, 'a');
+ VERIFY( in.gcount() == std::numeric_limits<std::streamsize>::max() );
+}
+
+int
+main()
+{
+ test01();
+}
diff --git a/libstdc++-v3/testsuite/27_io/basic_istream/get/wchar_t/lwg3464.cc b/libstdc++-v3/testsuite/27_io/basic_istream/get/wchar_t/lwg3464.cc
new file mode 100644
index 0000000..6df244c
--- /dev/null
+++ b/libstdc++-v3/testsuite/27_io/basic_istream/get/wchar_t/lwg3464.cc
@@ -0,0 +1,91 @@
+// Copyright (C) 2020 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 { ! lp64 } } }
+
+#include <istream>
+#include <streambuf>
+#include <limits>
+#include <testsuite_hooks.h>
+
+typedef wchar_t C;
+
+struct buff : std::basic_streambuf<C>
+{
+ typedef std::streamsize streamsize;
+ typedef std::numeric_limits<streamsize> limits;
+
+ buff() : count(0), buf() { }
+
+ int_type underflow()
+ {
+ // Number of characters left until we overflow the counter
+ const streamsize headroom = limits::max() - count;
+
+ if (headroom == 0)
+ return traits_type::eof();
+
+ if (bufsz < headroom)
+ count += bufsz;
+ else
+ count = limits::max();
+
+ this->setg(buf + 1, buf + 1, buf + bufsz);
+
+ return buf[0];
+ }
+
+ int_type overflow(int_type c)
+ {
+ if (traits_type::eq_int_type(c , traits_type::eof()))
+ return c;
+ this->setp(buf, buf + bufsz - 1);
+ return traits_type::not_eof(c);
+ }
+
+ streamsize count;
+
+ static const streamsize bufsz = (2048 << limits::digits10) + 1;
+ char_type buf[bufsz];
+};
+
+void
+test01()
+{
+ // Not possible to overflow 64-bit streamsize in reasonable time.
+ if (std::numeric_limits<std::streamsize>::digits > 32)
+ return;
+
+ std::basic_istream<C> in(new buff);
+ buff out;
+ in.get(out);
+ VERIFY( in.gcount() == std::numeric_limits<std::streamsize>::max() );
+
+ delete in.rdbuf(new buff);
+
+ in.get();
+ VERIFY( in.gcount() == 1 );
+
+ in.get(out, 'a');
+ VERIFY( in.gcount() == std::numeric_limits<std::streamsize>::max() );
+}
+
+int
+main()
+{
+ test01();
+}