diff options
author | Jonathan Wakely <jwakely@redhat.com> | 2020-08-05 22:17:18 +0100 |
---|---|---|
committer | Jonathan Wakely <jwakely@redhat.com> | 2020-08-05 22:17:18 +0100 |
commit | 17abcc773415848dce593016512636cda3de20d5 (patch) | |
tree | 388be0949b70820b6ea3b47999c64c151ab144c5 /libstdc++-v3/testsuite/27_io/basic_istream | |
parent | d21252de6c81ed236d8981d47b9a57dc4f1c6d57 (diff) | |
download | gcc-17abcc773415848dce593016512636cda3de20d5.zip gcc-17abcc773415848dce593016512636cda3de20d5.tar.gz gcc-17abcc773415848dce593016512636cda3de20d5.tar.bz2 |
libstdc++: Replace operator>>(istream&, char*) [LWG 2499]
P0487R1 resolved LWG 2499 for C++20 by removing the operator>> overloads
that have high risk of buffer overflows. They were replaced by
equivalents that only accept a reference to an array, and so can
guarantee not to write past the end of the array.
In order to support both the old and new functionality, this patch
introduces a new overloaded __istream_extract function which takes a
maximum length. The new operator>> overloads use the array size as the
maximum length. The old overloads now use __builtin_object_size to
determine the available buffer size if available (which requires -O2) or
use numeric_limits<streamsize>::max()/sizeof(char_type) otherwise. This
is a change in behaviour, as the old overloads previously always used
numeric_limits<streamsize>::max(), without considering sizeof(char_type)
and without attempting to prevent overflows.
Because they now do little more than call __istream_extract, the old
operator>> overloads are very small inline functions. This means there
is no advantage to explicitly instantiating them in the library (in fact
that would prevent the __builtin_object_size checks from ever working).
As a result, the explicit instantiation declarations can be removed from
the header. The explicit instantiation definitions are still needed, for
backwards compatibility with existing code that expects to link to the
definitions in the library.
While working on this change I noticed that src/c++11/istream-inst.cc
has the following explicit instantiation definition:
template istream& operator>>(istream&, char*);
This had no effect (and so should not have been present in that file),
because there was an explicit specialization declared in <istream> and
defined in src/++98/istream.cc. However, this change removes the
explicit specialization, and now the explicit instantiation definition
is necessary to ensure the symbol gets defined in the library.
libstdc++-v3/ChangeLog:
* config/abi/pre/gnu.ver (GLIBCXX_3.4.29): Export new symbols.
* include/bits/istream.tcc (__istream_extract): New function
template implementing both of operator>>(istream&, char*) and
operator>>(istream&, char(&)[N]). Add explicit instantiation
declaration for it. Remove explicit instantiation declarations
for old function templates.
* include/std/istream (__istream_extract): Declare.
(operator>>(basic_istream<C,T>&, C*)): Define inline and simply
call __istream_extract.
(operator>>(basic_istream<char,T>&, signed char*)): Likewise.
(operator>>(basic_istream<char,T>&, unsigned char*)): Likewise.
(operator>>(basic_istream<C,T>&, C(7)[N])): Define for LWG 2499.
(operator>>(basic_istream<char,T>&, signed char(&)[N])):
Likewise.
(operator>>(basic_istream<char,T>&, unsigned char(&)[N])):
Likewise.
* include/std/streambuf (basic_streambuf): Declare char overload
of __istream_extract as a friend.
* src/c++11/istream-inst.cc: Add explicit instantiation
definition for wchar_t overload of __istream_extract. Remove
explicit instantiation definitions of old operator>> overloads
for versioned-namespace build.
* src/c++98/istream.cc (operator>>(istream&, char*)): Replace
with __istream_extract(istream&, char*, streamsize).
* testsuite/27_io/basic_istream/extractors_character/char/3.cc:
Do not use variable-length array.
* testsuite/27_io/basic_istream/extractors_character/char/4.cc:
Do not run test for C++20.
* testsuite/27_io/basic_istream/extractors_character/char/9555-ic.cc:
Do not test writing to pointers for C++20.
* testsuite/27_io/basic_istream/extractors_character/char/9826.cc:
Use array instead of pointer.
* testsuite/27_io/basic_istream/extractors_character/wchar_t/3.cc:
Do not use variable-length array.
* testsuite/27_io/basic_istream/extractors_character/wchar_t/4.cc:
Do not run test for C++20.
* testsuite/27_io/basic_istream/extractors_character/wchar_t/9555-ic.cc:
Do not test writing to pointers for C++20.
* testsuite/27_io/basic_istream/extractors_character/char/lwg2499.cc:
New test.
* testsuite/27_io/basic_istream/extractors_character/char/lwg2499_neg.cc:
New test.
* testsuite/27_io/basic_istream/extractors_character/char/overflow.cc:
New test.
* testsuite/27_io/basic_istream/extractors_character/wchar_t/lwg2499.cc:
New test.
* testsuite/27_io/basic_istream/extractors_character/wchar_t/lwg2499_neg.cc:
New test.
Diffstat (limited to 'libstdc++-v3/testsuite/27_io/basic_istream')
12 files changed, 308 insertions, 3 deletions
diff --git a/libstdc++-v3/testsuite/27_io/basic_istream/extractors_character/char/3.cc b/libstdc++-v3/testsuite/27_io/basic_istream/extractors_character/char/3.cc index 2b7f086..32020b1b 100644 --- a/libstdc++-v3/testsuite/27_io/basic_istream/extractors_character/char/3.cc +++ b/libstdc++-v3/testsuite/27_io/basic_istream/extractors_character/char/3.cc @@ -39,7 +39,7 @@ void test01() // template<_CharT, _Traits> // basic_istream& operator>>(istream&, _CharT*) - int n = 20; + const int n = 20; char array1[n]; typedef std::ios::traits_type ctraits_type; diff --git a/libstdc++-v3/testsuite/27_io/basic_istream/extractors_character/char/4.cc b/libstdc++-v3/testsuite/27_io/basic_istream/extractors_character/char/4.cc index c7c5401..9e427cc 100644 --- a/libstdc++-v3/testsuite/27_io/basic_istream/extractors_character/char/4.cc +++ b/libstdc++-v3/testsuite/27_io/basic_istream/extractors_character/char/4.cc @@ -19,6 +19,7 @@ // 27.6.1.2.3 basic_istream::operator>> +// { dg-do run { target { ! c++20 } } } // { dg-require-fileio "" } #include <istream> diff --git a/libstdc++-v3/testsuite/27_io/basic_istream/extractors_character/char/9555-ic.cc b/libstdc++-v3/testsuite/27_io/basic_istream/extractors_character/char/9555-ic.cc index c38b7ea..d5d86c6 100644 --- a/libstdc++-v3/testsuite/27_io/basic_istream/extractors_character/char/9555-ic.cc +++ b/libstdc++-v3/testsuite/27_io/basic_istream/extractors_character/char/9555-ic.cc @@ -60,9 +60,11 @@ int main() testthrow(c); testthrow(uc); testthrow(sc); +#if __cplusplus <= 201703L testthrow(cp); testthrow(scp); testthrow(ucp); +#endif return 0; } diff --git a/libstdc++-v3/testsuite/27_io/basic_istream/extractors_character/char/9826.cc b/libstdc++-v3/testsuite/27_io/basic_istream/extractors_character/char/9826.cc index 07ee251..bc77f7b 100644 --- a/libstdc++-v3/testsuite/27_io/basic_istream/extractors_character/char/9826.cc +++ b/libstdc++-v3/testsuite/27_io/basic_istream/extractors_character/char/9826.cc @@ -39,7 +39,7 @@ void test02() sstr >> str; // 2 - pod_char* chr = 0; + pod_char chr[1]; sstr >> chr; // 3 diff --git a/libstdc++-v3/testsuite/27_io/basic_istream/extractors_character/char/lwg2499.cc b/libstdc++-v3/testsuite/27_io/basic_istream/extractors_character/char/lwg2499.cc new file mode 100644 index 0000000..d77b711 --- /dev/null +++ b/libstdc++-v3/testsuite/27_io/basic_istream/extractors_character/char/lwg2499.cc @@ -0,0 +1,80 @@ +// 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-options "-std=gnu++2a" } +// { dg-do run { target c++2a } } + +// LWG 2499 +// operator>>(basic_istream&, CharT*) makes it hard to avoid buffer overflows + +#include <sstream> +#include <testsuite_hooks.h> + +template<typename T> +void +test(std::basic_istream<char, T>& in) +{ + char pc[3]; + in >> pc; + VERIFY( in.good() ); + VERIFY( pc[0] == 'a' && pc[1] == 'b' && pc[2] == '\0' ); + + signed char sc[4]; + in >> sc; + VERIFY( in.good() ); + VERIFY( sc[0] == 'c' && sc[1] == 'd' && sc[2] == 'e' && sc[3] == '\0' ); + + unsigned char uc[4]; + in >> uc; + VERIFY( in.good() ); + VERIFY( uc[0] == 'f' && uc[1] == 'g' && uc[2] == 'h' && uc[3] == '\0' ); + + pc[2] = '#'; + in >> pc; + VERIFY( in.good() ); + VERIFY( pc[0] == 'i' && pc[1] == '\0' && pc[2] == '#' ); + + in >> pc; + VERIFY( in.good() ); + VERIFY( pc[0] == 'j' && pc[1] == 'k' && pc[2] == '\0' ); + + pc[2] = '#'; + in >> pc; + VERIFY( in.eof() ); + VERIFY( pc[0] == 'l' && pc[1] == '\0' && pc[2] == '#' ); +} + +void +test01() +{ + std::istringstream in("abcdefghi jk l"); + test(in); +} + +void +test02() +{ + struct CT : std::char_traits<char> { }; + std::basic_istringstream<char, CT> in("abcdefghi jk l"); + test(in); +} + +int main() +{ + test01(); + test02(); +} diff --git a/libstdc++-v3/testsuite/27_io/basic_istream/extractors_character/char/lwg2499_neg.cc b/libstdc++-v3/testsuite/27_io/basic_istream/extractors_character/char/lwg2499_neg.cc new file mode 100644 index 0000000..2c2bd52 --- /dev/null +++ b/libstdc++-v3/testsuite/27_io/basic_istream/extractors_character/char/lwg2499_neg.cc @@ -0,0 +1,45 @@ +// 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-options "-std=gnu++2a" } +// { dg-do compile { target c++2a } } + +// LWG 2499 +// operator>>(basic_istream&, CharT*) makes it hard to avoid buffer overflows + +#include <istream> + +void +test01(std::istream& in, char* pc, signed char* sc, unsigned char* uc) +{ + in >> pc; // { dg-error "here" } + in >> sc; // { dg-error "here" } + in >> uc; // { dg-error "here" } +} + +struct CT : std::char_traits<char> { }; + +void +test02(std::basic_istream<char, CT>& in, char* pc, signed char* sc, + unsigned char* uc) +{ + in >> pc; // { dg-error "here" } + in >> sc; // { dg-error "here" } + in >> uc; // { dg-error "here" } +} + +// { dg-excess-errors "" } diff --git a/libstdc++-v3/testsuite/27_io/basic_istream/extractors_character/char/overflow.cc b/libstdc++-v3/testsuite/27_io/basic_istream/extractors_character/char/overflow.cc new file mode 100644 index 0000000..1141a41 --- /dev/null +++ b/libstdc++-v3/testsuite/27_io/basic_istream/extractors_character/char/overflow.cc @@ -0,0 +1,64 @@ +// 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-options "-O2 -std=gnu++98" } +// { dg-do run } + +// This test checks that operator>> will avoid a buffer overflow when +// reading into a buffer with a size that is known at compile time. + +// Since C++20 this is guaranteed (see LWG 2499), for previous standards +// we try to check the buffer size as an extension (which depends on -O2). + +#include <sstream> +#include <testsuite_hooks.h> + +void +test01() +{ + std::istringstream in("foolish child"); + char pc[5]; + in >> pc; + VERIFY( in.good() ); + VERIFY( std::string(pc) == "fool" ); +} + +void +test02() +{ + std::istringstream in("foolish"); + signed char sc[5]; + in >> sc; + VERIFY( in.good() ); + VERIFY( std::string((const char*)sc) == "fool" ); +} + +void +test03() +{ + std::istringstream in("foolish"); + unsigned char uc[5]; + in >> uc; + VERIFY( in.good() ); + VERIFY( std::string((const char*)uc) == "fool" ); +} + +int +main() +{ + test01(); +} diff --git a/libstdc++-v3/testsuite/27_io/basic_istream/extractors_character/wchar_t/3.cc b/libstdc++-v3/testsuite/27_io/basic_istream/extractors_character/wchar_t/3.cc index 0ba58f7..5ee3ee1 100644 --- a/libstdc++-v3/testsuite/27_io/basic_istream/extractors_character/wchar_t/3.cc +++ b/libstdc++-v3/testsuite/27_io/basic_istream/extractors_character/wchar_t/3.cc @@ -37,7 +37,7 @@ void test01() // template<_CharT, _Traits> // basic_istream& operator>>(istream&, _CharT*) - int n = 20; + const int n = 20; wchar_t array1[n]; typedef std::wios::traits_type ctraits_type; diff --git a/libstdc++-v3/testsuite/27_io/basic_istream/extractors_character/wchar_t/4.cc b/libstdc++-v3/testsuite/27_io/basic_istream/extractors_character/wchar_t/4.cc index 6c3ee64..8414d62 100644 --- a/libstdc++-v3/testsuite/27_io/basic_istream/extractors_character/wchar_t/4.cc +++ b/libstdc++-v3/testsuite/27_io/basic_istream/extractors_character/wchar_t/4.cc @@ -20,6 +20,7 @@ // 27.6.1.2.3 basic_istream::operator>> // { dg-options "-DMAX_SIZE=466" { target simulator } } +// { dg-do run { target { ! c++20 } } } // { dg-require-fileio "" } #ifndef MAX_SIZE diff --git a/libstdc++-v3/testsuite/27_io/basic_istream/extractors_character/wchar_t/9555-ic.cc b/libstdc++-v3/testsuite/27_io/basic_istream/extractors_character/wchar_t/9555-ic.cc index c4935b7..1a9f9aa 100644 --- a/libstdc++-v3/testsuite/27_io/basic_istream/extractors_character/wchar_t/9555-ic.cc +++ b/libstdc++-v3/testsuite/27_io/basic_istream/extractors_character/wchar_t/9555-ic.cc @@ -54,7 +54,9 @@ int main() wchar_t* cp = &c; testthrow(c); +#if __cplusplus <= 201703L testthrow(cp); +#endif return 0; } diff --git a/libstdc++-v3/testsuite/27_io/basic_istream/extractors_character/wchar_t/lwg2499.cc b/libstdc++-v3/testsuite/27_io/basic_istream/extractors_character/wchar_t/lwg2499.cc new file mode 100644 index 0000000..e1d42b4 --- /dev/null +++ b/libstdc++-v3/testsuite/27_io/basic_istream/extractors_character/wchar_t/lwg2499.cc @@ -0,0 +1,70 @@ +// 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-options "-std=gnu++2a" } +// { dg-do compile { target c++2a } } + +// LWG 2499 +// operator>>(basic_istream&, CharT*) makes it hard to avoid buffer overflows + +#include <sstream> +#include <testsuite_hooks.h> + +template<typename T> +void +test(std::basic_istream<wchar_t, T>& in) +{ + wchar_t wc[3]; + in >> wc; + VERIFY( in.good() ); + VERIFY( wc[0] == L'a' && wc[1] == L'b' && wc[2] == L'\0' ); + + wc[2] = L'#'; + in >> wc; + VERIFY( in.good() ); + VERIFY( wc[0] == L'c' && wc[1] == L'\0' && wc[2] == L'#' ); + + in >> wc; + VERIFY( in.good() ); + VERIFY( wc[0] == L'd' && wc[1] == L'\0' && wc[2] == L'#' ); + + wc[2] = L'#'; + in >> wc; + VERIFY( in.eof() ); + VERIFY( wc[0] == L'e' && wc[1] == L'\0' && wc[2] == L'#' ); +} + +void +test01() +{ + std::wistringstream in(L"abc d e"); + test(in); +} + +void +test02() +{ + struct WT : std::char_traits<wchar_t> { }; + std::basic_istringstream<wchar_t, WT> in(L"abc d e"); + test(in); +} + +int main() +{ + test01(); + test02(); +} diff --git a/libstdc++-v3/testsuite/27_io/basic_istream/extractors_character/wchar_t/lwg2499_neg.cc b/libstdc++-v3/testsuite/27_io/basic_istream/extractors_character/wchar_t/lwg2499_neg.cc new file mode 100644 index 0000000..676cdee82 --- /dev/null +++ b/libstdc++-v3/testsuite/27_io/basic_istream/extractors_character/wchar_t/lwg2499_neg.cc @@ -0,0 +1,40 @@ +// 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-options "-std=gnu++2a" } +// { dg-do compile { target c++2a } } + +// LWG 2499 +// operator>>(basic_istream&, CharT*) makes it hard to avoid buffer overflows + +#include <istream> + +void +test01(std::wistream& in, wchar_t* wc) +{ + in >> wc; // { dg-error "here" } +} + +struct WT : std::char_traits<wchar_t> { }; + +void +test02(std::basic_istream<wchar_t, WT>& in, wchar_t* wc) +{ + in >> wc; // { dg-error "here" } +} + +// { dg-excess-errors "" } |