Here's a patch to replace the unsafe, unbounded operator>> with the new one that only allows reading into a fixed-size array.
I think I'll sit on this until stage1 though. The other options are to bump the libstdc++.so version and add it now, or not bump the version and also add the new symbol on gcc-9-branch.
diff --git a/libstdc++-v3/config/abi/pre/gnu.ver b/libstdc++-v3/config/abi/pre/gnu.ver index edf4485e607..00cae801dfc 100644 --- a/libstdc++-v3/config/abi/pre/gnu.ver +++ b/libstdc++-v3/config/abi/pre/gnu.ver @@ -2297,6 +2297,9 @@ GLIBCXX_3.4.28 { _ZNSt3pmr25monotonic_buffer_resourceD[0125]Ev; _ZT[ISV]NSt3pmr25monotonic_buffer_resourceE; + # std::__extract_to_array(std:istream&, char*, streamsize) + _ZSt18__extract_to_arrayRSiPc[ilx]; + } GLIBCXX_3.4.27; # Symbols in the support library (libsupc++) have their own tag. diff --git a/libstdc++-v3/include/bits/istream.tcc b/libstdc++-v3/include/bits/istream.tcc index c82da56b9f9..fb4a73a8539 100644 --- a/libstdc++-v3/include/bits/istream.tcc +++ b/libstdc++-v3/include/bits/istream.tcc @@ -958,9 +958,23 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION return __in; } +#if __cplusplus <= 201703L template<typename _CharT, typename _Traits> basic_istream<_CharT, _Traits>& operator>>(basic_istream<_CharT, _Traits>& __in, _CharT* __s) +#else + template<size_t _Num> + basic_istream<char>& + operator>>(basic_istream<char>& __in, char (&__s)[_Num]) + { + static_assert(_Num <= __gnu_cxx::__numeric_traits<streamsize>::__max); + return std::__extract_to_array(__in, __s, _Num); + } + + template<typename _CharT, typename _Traits, size_t _Num> + basic_istream<_CharT, _Traits>& + operator>>(basic_istream<_CharT, _Traits>& __in, _CharT (&__a)[_Num]) +#endif { typedef basic_istream<_CharT, _Traits> __istream_type; typedef basic_streambuf<_CharT, _Traits> __streambuf_type; @@ -977,8 +991,14 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION { // Figure out how many characters to extract. streamsize __num = __in.width(); +#if __cplusplus <= 201703L if (__num <= 0) __num = __gnu_cxx::__numeric_traits<streamsize>::__max; +#else + if (__num <= 0 || (size_t)__num > _Num) + __num = _Num; + _CharT* __s = __a; +#endif const __ctype_type& __ct = use_facet<__ctype_type>(__in.getloc()); @@ -1048,11 +1068,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION extern template class basic_istream<char>; extern template istream& ws(istream&); extern template istream& operator>>(istream&, char&); - extern template istream& operator>>(istream&, char*); extern template istream& operator>>(istream&, unsigned char&); extern template istream& operator>>(istream&, signed char&); +#if __cplusplus <= 201703L + extern template istream& operator>>(istream&, char*); extern template istream& operator>>(istream&, unsigned char*); extern template istream& operator>>(istream&, signed char*); +#endif extern template istream& istream::_M_extract(unsigned short&); extern template istream& istream::_M_extract(unsigned int&); @@ -1074,7 +1096,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION extern template class basic_istream<wchar_t>; extern template wistream& ws(wistream&); extern template wistream& operator>>(wistream&, wchar_t&); +#if __cplusplus <= 201703L extern template wistream& operator>>(wistream&, wchar_t*); +#endif extern template wistream& wistream::_M_extract(unsigned short&); extern template wistream& wistream::_M_extract(unsigned int&); diff --git a/libstdc++-v3/include/std/istream b/libstdc++-v3/include/std/istream index 407c1ccda49..47764604eff 100644 --- a/libstdc++-v3/include/std/istream +++ b/libstdc++-v3/include/std/istream @@ -789,6 +789,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION * * If no characters are extracted, sets failbit. */ +#if __cplusplus <= 201703L template<typename _CharT, typename _Traits> basic_istream<_CharT, _Traits>& operator>>(basic_istream<_CharT, _Traits>& __in, _CharT* __s); @@ -807,6 +808,22 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION inline basic_istream<char, _Traits>& operator>>(basic_istream<char, _Traits>& __in, signed char* __s) { return (__in >> reinterpret_cast<char*>(__s)); } + +#else // C++20 + template<typename _CharT, typename _Traits, size_t _Num> + basic_istream<_CharT, _Traits>& + operator>>(basic_istream<_CharT, _Traits>& __in, _CharT (&__s)[_Num]); + + template<class _Traits, size_t _Num> + inline basic_istream<char, _Traits>& + operator>>(basic_istream<char, _Traits>& __in, unsigned char (&__s)[_Num]) + { return (__in >> reinterpret_cast<char(&)[_Num]>(__s)); } + + template<class _Traits, size_t _Num> + inline basic_istream<char, _Traits>& + operator>>(basic_istream<char, _Traits>& __in, signed char (&__s)[_Num]) + { return (__in >> reinterpret_cast<char(&)[_Num]>(__s)); } +#endif //@} /** diff --git a/libstdc++-v3/include/std/streambuf b/libstdc++-v3/include/std/streambuf index f8e4cb9879c..89ccfe27e23 100644 --- a/libstdc++-v3/include/std/streambuf +++ b/libstdc++-v3/include/std/streambuf @@ -53,6 +53,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION __copy_streambufs_eof(basic_streambuf<_CharT, _Traits>*, basic_streambuf<_CharT, _Traits>*, bool&); + basic_istream<char>& + __extract_to_array(basic_istream<char>&, char*, streamsize); + /** * @brief The actual work of input and output (interface). * @ingroup io @@ -166,10 +169,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION void>::__type advance(istreambuf_iterator<_CharT2>&, _Distance); - template<typename _CharT2, typename _Traits2> - friend basic_istream<_CharT2, _Traits2>& - operator>>(basic_istream<_CharT2, _Traits2>&, _CharT2*); - template<typename _CharT2, typename _Traits2, typename _Alloc> friend basic_istream<_CharT2, _Traits2>& operator>>(basic_istream<_CharT2, _Traits2>&, @@ -180,6 +179,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION getline(basic_istream<_CharT2, _Traits2>&, basic_string<_CharT2, _Traits2, _Alloc>&, _CharT2); + friend basic_istream<char>& + __extract_to_array(basic_istream<char>&, char*, streamsize); + protected: /* * This is based on _IO_FILE, just reordered to be more consistent, diff --git a/libstdc++-v3/src/c++98/istream.cc b/libstdc++-v3/src/c++98/istream.cc index 79d829e23b4..27b1a3f0e64 100644 --- a/libstdc++-v3/src/c++98/istream.cc +++ b/libstdc++-v3/src/c++98/istream.cc @@ -192,85 +192,92 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION return *this; } + basic_istream<char>& + __extract_to_array(basic_istream<char>& __in, char* __s, streamsize __maxnum) + { + typedef basic_istream<char> __istream_type; + typedef __istream_type::int_type __int_type; + typedef __istream_type::char_type __char_type; + typedef __istream_type::traits_type __traits_type; + typedef __istream_type::__streambuf_type __streambuf_type; + typedef __istream_type::__ctype_type __ctype_type; + + streamsize __extracted = 0; + ios_base::iostate __err = ios_base::goodbit; + __istream_type::sentry __cerb(__in, false); + if (__cerb) + { + __try + { + // Figure out how many characters to extract. + streamsize __num = __in.width(); + if (__num <= 0 || __num > __maxnum) + __num = __maxnum; + + const __ctype_type& __ct = use_facet<__ctype_type>(__in.getloc()); + + const __int_type __eof = __traits_type::eof(); + __streambuf_type* __sb = __in.rdbuf(); + __int_type __c = __sb->sgetc(); + + while (__extracted < __num - 1 + && !__traits_type::eq_int_type(__c, __eof) + && !__ct.is(ctype_base::space, + __traits_type::to_char_type(__c))) + { + streamsize __size = std::min(streamsize(__sb->egptr() + - __sb->gptr()), + streamsize(__num - __extracted + - 1)); + if (__size > 1) + { + __size = (__ct.scan_is(ctype_base::space, + __sb->gptr() + 1, + __sb->gptr() + __size) + - __sb->gptr()); + __traits_type::copy(__s, __sb->gptr(), __size); + __s += __size; + __sb->__safe_gbump(__size); + __extracted += __size; + __c = __sb->sgetc(); + } + else + { + *__s++ = __traits_type::to_char_type(__c); + ++__extracted; + __c = __sb->snextc(); + } + } + + if (__traits_type::eq_int_type(__c, __eof)) + __err |= ios_base::eofbit; + + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 68. Extractors for char* should store null at end + *__s = __char_type(); + __in.width(0); + } + __catch(__cxxabiv1::__forced_unwind&) + { + __in._M_setstate(ios_base::badbit); + __throw_exception_again; + } + __catch(...) + { __in._M_setstate(ios_base::badbit); } + } + if (!__extracted) + __err |= ios_base::failbit; + if (__err) + __in.setstate(__err); + return __in; + } + template<> basic_istream<char>& operator>>(basic_istream<char>& __in, char* __s) { - typedef basic_istream<char> __istream_type; - typedef __istream_type::int_type __int_type; - typedef __istream_type::char_type __char_type; - typedef __istream_type::traits_type __traits_type; - typedef __istream_type::__streambuf_type __streambuf_type; - typedef __istream_type::__ctype_type __ctype_type; - - streamsize __extracted = 0; - ios_base::iostate __err = ios_base::goodbit; - __istream_type::sentry __cerb(__in, false); - if (__cerb) - { - __try - { - // Figure out how many characters to extract. - streamsize __num = __in.width(); - if (__num <= 0) - __num = __gnu_cxx::__numeric_traits<streamsize>::__max; - - const __ctype_type& __ct = use_facet<__ctype_type>(__in.getloc()); - - const __int_type __eof = __traits_type::eof(); - __streambuf_type* __sb = __in.rdbuf(); - __int_type __c = __sb->sgetc(); - - while (__extracted < __num - 1 - && !__traits_type::eq_int_type(__c, __eof) - && !__ct.is(ctype_base::space, - __traits_type::to_char_type(__c))) - { - streamsize __size = std::min(streamsize(__sb->egptr() - - __sb->gptr()), - streamsize(__num - __extracted - - 1)); - if (__size > 1) - { - __size = (__ct.scan_is(ctype_base::space, - __sb->gptr() + 1, - __sb->gptr() + __size) - - __sb->gptr()); - __traits_type::copy(__s, __sb->gptr(), __size); - __s += __size; - __sb->__safe_gbump(__size); - __extracted += __size; - __c = __sb->sgetc(); - } - else - { - *__s++ = __traits_type::to_char_type(__c); - ++__extracted; - __c = __sb->snextc(); - } - } - - if (__traits_type::eq_int_type(__c, __eof)) - __err |= ios_base::eofbit; - - // _GLIBCXX_RESOLVE_LIB_DEFECTS - // 68. Extractors for char* should store null at end - *__s = __char_type(); - __in.width(0); - } - __catch(__cxxabiv1::__forced_unwind&) - { - __in._M_setstate(ios_base::badbit); - __throw_exception_again; - } - __catch(...) - { __in._M_setstate(ios_base::badbit); } - } - if (!__extracted) - __err |= ios_base::failbit; - if (__err) - __in.setstate(__err); - return __in; + return std::__extract_to_array(__in, __s, + __gnu_cxx::__numeric_traits<streamsize>::__max); } #ifdef _GLIBCXX_USE_WCHAR_T