diff options
Diffstat (limited to 'libstdc++-v3')
3 files changed, 190 insertions, 1 deletions
diff --git a/libstdc++-v3/include/bits/istream.tcc b/libstdc++-v3/include/bits/istream.tcc index 5983e51..0289867 100644 --- a/libstdc++-v3/include/bits/istream.tcc +++ b/libstdc++-v3/include/bits/istream.tcc @@ -375,17 +375,24 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION __streambuf_type* __this_sb = this->rdbuf(); int_type __c = __this_sb->sgetc(); char_type __c2 = traits_type::to_char_type(__c); + unsigned long long __gcount = 0; while (!traits_type::eq_int_type(__c, __eof) && !traits_type::eq_int_type(__c, __idelim) && !traits_type::eq_int_type(__sb.sputc(__c2), __eof)) { - ++_M_gcount; + ++__gcount; __c = __this_sb->snextc(); __c2 = traits_type::to_char_type(__c); } if (traits_type::eq_int_type(__c, __eof)) __err |= ios_base::eofbit; + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 3464. istream::gcount() can overflow + if (__gcount <= __gnu_cxx::__numeric_traits<streamsize>::__max) + _M_gcount = __gcount; + else + _M_gcount = __gnu_cxx::__numeric_traits<streamsize>::__max; } __catch(__cxxabiv1::__forced_unwind&) { 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(); +} |