From patchwork Sat Jan 11 01:22:08 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jonathan Wakely X-Patchwork-Id: 1221521 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=gcc.gnu.org (client-ip=209.132.180.131; helo=sourceware.org; envelope-from=gcc-patches-return-517206-incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=redhat.com Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=gcc.gnu.org header.i=@gcc.gnu.org header.a=rsa-sha1 header.s=default header.b=NhrbMoA8; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=ZNNBREO7; dkim-atps=neutral Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 47vht456V7z9sPn for ; Sat, 11 Jan 2020 12:22:36 +1100 (AEDT) DomainKey-Signature: a=rsa-sha1; c=nofws; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:date :from:to:subject:message-id:mime-version:content-type; q=dns; s= default; b=FCfttH8YslNsV7+SLN+fbaA62XbwsK7lyRtR4cXCdLVoMALuVvZSX cSW/Z2Idrym1DtKxiFxOG+4/5M3gLxRWhBriL/RfDx0nLt5f3Bv7wqVVhTV8PS85 1xqo/C1oO6yZhmd5NSV+4r9n2OvEofo7y+EXGt2AxVGHrtYnR5FjhQ= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:date :from:to:subject:message-id:mime-version:content-type; s= default; bh=spif/bHSfaBXwfERpHti7lDKl/4=; b=NhrbMoA8BDsu3/HWMxZ6 LSt1Do7EHemJg5lcKpOoKMbQKeYao0PeVuD87bHKQ1yqCj8JB47aNII3ghEMWEyy KI6w3sP+p91nmyaRux0OuK0IE37FVvMZqF512O/OfTpoqwxrjX7GHeimZW5ltm2I 6497vEpAfXNzY2nYBzBMlIc= Received: (qmail 87762 invoked by alias); 11 Jan 2020 01:22:18 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org Received: (qmail 87709 invoked by uid 89); 11 Jan 2020 01:22:17 -0000 Authentication-Results: sourceware.org; auth=none X-Spam-SWARE-Status: No, score=-17.7 required=5.0 tests=AWL, BAYES_00, GIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, RCVD_IN_DNSWL_NONE autolearn=unavailable version=3.3.1 spammy=__ct, UD:gnu.ver, UD:ver, gnu.ver X-HELO: us-smtp-1.mimecast.com Received: from us-smtp-delivery-1.mimecast.com (HELO us-smtp-1.mimecast.com) (205.139.110.120) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Sat, 11 Jan 2020 01:22:15 +0000 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1578705734; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type; bh=/+/XFPTHEFylDD75gmgdO3NSdrrSgLiMGXZ16TV9HmY=; b=ZNNBREO7LIYDAmoHv0yKf6AztIcxk0xzRPvdqz3VI1dMYbZEaBAGHGBISHYL710Lli5nNt BsoliyEZ8ekYmxRAMkJcIekyQZ/X0eDWg/wFDl1pzBb3idCcZg4eykObrczKnlp9/9GdRD 5vBiKPUQFqKXWyGElL39NIU5PVZcfag= Received: from mimecast-mx01.redhat.com (mimecast-mx01.redhat.com [209.132.183.4]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-408-2nr2fNWhMLamLwTVCzNpcA-1; Fri, 10 Jan 2020 20:22:10 -0500 Received: from smtp.corp.redhat.com (int-mx05.intmail.prod.int.phx2.redhat.com [10.5.11.15]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id 92924800D41; Sat, 11 Jan 2020 01:22:09 +0000 (UTC) Received: from localhost (unknown [10.33.36.12]) by smtp.corp.redhat.com (Postfix) with ESMTP id EA3BC5D72B; Sat, 11 Jan 2020 01:22:08 +0000 (UTC) Date: Sat, 11 Jan 2020 01:22:08 +0000 From: Jonathan Wakely To: libstdc++@gcc.gnu.org, gcc-patches@gcc.gnu.org Subject: [PATCH] libstdc++/88812 C++20 LWG 2499/P0487R1 - Fixing operator>>(basic_istream&, CharT*) Message-ID: <20200111012208.GH490107@redhat.com> MIME-Version: 1.0 X-Clacks-Overhead: GNU Terry Pratchett X-Mimecast-Spam-Score: 0 Content-Disposition: inline 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 basic_istream<_CharT, _Traits>& operator>>(basic_istream<_CharT, _Traits>& __in, _CharT* __s) +#else + template + basic_istream& + operator>>(basic_istream& __in, char (&__s)[_Num]) + { + static_assert(_Num <= __gnu_cxx::__numeric_traits::__max); + return std::__extract_to_array(__in, __s, _Num); + } + + template + 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::__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; 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; 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 basic_istream<_CharT, _Traits>& operator>>(basic_istream<_CharT, _Traits>& __in, _CharT* __s); @@ -807,6 +808,22 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION inline basic_istream& operator>>(basic_istream& __in, signed char* __s) { return (__in >> reinterpret_cast(__s)); } + +#else // C++20 + template + basic_istream<_CharT, _Traits>& + operator>>(basic_istream<_CharT, _Traits>& __in, _CharT (&__s)[_Num]); + + template + inline basic_istream& + operator>>(basic_istream& __in, unsigned char (&__s)[_Num]) + { return (__in >> reinterpret_cast(__s)); } + + template + inline basic_istream& + operator>>(basic_istream& __in, signed char (&__s)[_Num]) + { return (__in >> reinterpret_cast(__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& + __extract_to_array(basic_istream&, 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 - friend basic_istream<_CharT2, _Traits2>& - operator>>(basic_istream<_CharT2, _Traits2>&, _CharT2*); - template 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& + __extract_to_array(basic_istream&, 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& + __extract_to_array(basic_istream& __in, char* __s, streamsize __maxnum) + { + typedef basic_istream __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& operator>>(basic_istream& __in, char* __s) { - typedef basic_istream __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::__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::__max); } #ifdef _GLIBCXX_USE_WCHAR_T