[committed] libstdc++: Replace operator>>(istream&, char*) [LWG 2499]
Martin Sebor
msebor@redhat.com
Wed Aug 5 22:31:08 GMT 2020
On 8/5/20 3:25 PM, Jonathan Wakely wrote:
> 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.
>
> Tested powerpc64le-linux. Committed to trunk.
>
> Martin, Jakub, could you please double-check the usage of
> __builtin_object_size? (line 805 in libstdc++-v3/include/std/istream)
> Do you see any problems with using it here? If it can't tell the size
> then we just assume it's larger than the string to be extracted, which
> is what the old code did anyway. I do have an idea for stronger
> checking in debug mode, which I'll post in a minute.
I've always found the second argument to __builtin_object_size
confusing for types above 1. I don't see anything wrong in
the diff but I believe the most useful results are with type 1
for string functions and type 0 for raw memory functions like
memcpy (that's what _FORTIFY_SOURCE uses for the two sets of
functions). In type 2 when the result is zero it means one of
two things: either the size of the array couldn't be determined
or it really is zero. That's less than helpful in cases like:
char a[8];
strcpy (a + 8, s);
where it prevents detecting the buffer overflow.
I would suggest to use type 1 in the iostream functions instead.
Adding attribute access to the __istream_extract overloads should
also let GCC check for out-of-bounds accesses by the function and
issue warnings. This goes beyond what __builtin_object_size makes
possible (it considers also variable sizes in known ranges).
Martin
More information about the Gcc-patches
mailing list