diff options
| author | Zhihao Yuan <zy@miator.net> | 2018-11-21 03:30:10 +0000 |
|---|---|---|
| committer | Zhihao Yuan <zy@miator.net> | 2018-11-21 03:30:10 +0000 |
| commit | 147b25b4a146be2a2b4d37c9388b7fb51d5508f4 (patch) | |
| tree | c7d029c9957526b41c51747e7c30b44fa48b1b86 | |
| parent | 5cf902ccd42b59179e98409d6e9e1b5c206b9d06 (diff) | |
| download | bcm5719-llvm-147b25b4a146be2a2b4d37c9388b7fb51d5508f4.tar.gz bcm5719-llvm-147b25b4a146be2a2b4d37c9388b7fb51d5508f4.zip | |
[libc++] Implement P0487R1 - Fixing operator>>(basic_istream&, CharT*)
Summary:
Avoid buffer overflow by replacing the pointer interface with an array reference interface in C++2a.
Tentatively ready on Batavia2018.
https://wg21.link/lwg2499
https://wg21.link/p0487
Reviewers: mclow.lists, ldionne, EricWF
Reviewed By: ldionne
Subscribers: libcxx-commits, cfe-commits, christof
Differential Revision: https://reviews.llvm.org/D51268
llvm-svn: 347377
5 files changed, 127 insertions, 9 deletions
diff --git a/libcxx/include/istream b/libcxx/include/istream index e46881efe94..8487dbebae5 100644 --- a/libcxx/include/istream +++ b/libcxx/include/istream @@ -517,8 +517,9 @@ basic_istream<_CharT, _Traits>::operator>>(int& __n) } template<class _CharT, class _Traits> +_LIBCPP_INLINE_VISIBILITY basic_istream<_CharT, _Traits>& -operator>>(basic_istream<_CharT, _Traits>& __is, _CharT* __s) +__input_c_string(basic_istream<_CharT, _Traits>& __is, _CharT* __p, size_t __n) { #ifndef _LIBCPP_NO_EXCEPTIONS try @@ -527,13 +528,10 @@ operator>>(basic_istream<_CharT, _Traits>& __is, _CharT* __s) typename basic_istream<_CharT, _Traits>::sentry __sen(__is); if (__sen) { - streamsize __n = __is.width(); - if (__n <= 0) - __n = numeric_limits<streamsize>::max() / sizeof(_CharT) - 1; - streamsize __c = 0; + auto __s = __p; const ctype<_CharT>& __ct = use_facet<ctype<_CharT> >(__is.getloc()); ios_base::iostate __err = ios_base::goodbit; - while (__c < __n-1) + while (__s != __p + (__n-1)) { typename _Traits::int_type __i = __is.rdbuf()->sgetc(); if (_Traits::eq_int_type(__i, _Traits::eof())) @@ -545,12 +543,11 @@ operator>>(basic_istream<_CharT, _Traits>& __is, _CharT* __s) if (__ct.is(__ct.space, __ch)) break; *__s++ = __ch; - ++__c; __is.rdbuf()->sbumpc(); } *__s = _CharT(); __is.width(0); - if (__c == 0) + if (__s == __p) __err |= ios_base::failbit; __is.setstate(__err); } @@ -564,6 +561,48 @@ operator>>(basic_istream<_CharT, _Traits>& __is, _CharT* __s) return __is; } +#if _LIBCPP_STD_VER > 17 + +template<class _CharT, class _Traits, size_t _Np> +inline _LIBCPP_INLINE_VISIBILITY +basic_istream<_CharT, _Traits>& +operator>>(basic_istream<_CharT, _Traits>& __is, _CharT (&__buf)[_Np]) +{ + auto __n = _Np; + if (__is.width() > 0) + __n = _VSTD::min(size_t(__is.width()), _Np); + return _VSTD::__input_c_string(__is, __buf, __n); +} + +template<class _Traits, size_t _Np> +inline _LIBCPP_INLINE_VISIBILITY +basic_istream<char, _Traits>& +operator>>(basic_istream<char, _Traits>& __is, unsigned char (&__buf)[_Np]) +{ + return __is >> (char(&)[_Np])__buf; +} + +template<class _Traits, size_t _Np> +inline _LIBCPP_INLINE_VISIBILITY +basic_istream<char, _Traits>& +operator>>(basic_istream<char, _Traits>& __is, signed char (&__buf)[_Np]) +{ + return __is >> (char(&)[_Np])__buf; +} + +#else + +template<class _CharT, class _Traits> +inline _LIBCPP_INLINE_VISIBILITY +basic_istream<_CharT, _Traits>& +operator>>(basic_istream<_CharT, _Traits>& __is, _CharT* __s) +{ + streamsize __n = __is.width(); + if (__n <= 0) + __n = numeric_limits<streamsize>::max() / sizeof(_CharT) - 1; + return _VSTD::__input_c_string(__is, __s, size_t(__n)); +} + template<class _Traits> inline _LIBCPP_INLINE_VISIBILITY basic_istream<char, _Traits>& @@ -580,6 +619,8 @@ operator>>(basic_istream<char, _Traits>& __is, signed char* __s) return __is >> (char*)__s; } +#endif // _LIBCPP_STD_VER > 17 + template<class _CharT, class _Traits> basic_istream<_CharT, _Traits>& operator>>(basic_istream<_CharT, _Traits>& __is, _CharT& __c) diff --git a/libcxx/test/std/input.output/iostream.format/input.streams/istream.formatted/istream_extractors/signed_char_pointer.pass.cpp b/libcxx/test/std/input.output/iostream.format/input.streams/istream.formatted/istream_extractors/signed_char_pointer.pass.cpp index 70f1c20108f..b815246d6c1 100644 --- a/libcxx/test/std/input.output/iostream.format/input.streams/istream.formatted/istream_extractors/signed_char_pointer.pass.cpp +++ b/libcxx/test/std/input.output/iostream.format/input.streams/istream.formatted/istream_extractors/signed_char_pointer.pass.cpp @@ -61,6 +61,17 @@ int main() assert(std::string((char*)s) == "abc"); assert(is.width() == 0); } +#if TEST_STD_VER > 17 + { + testbuf<char> sb(" abcdefghijk "); + std::istream is(&sb); + signed char s[4]; + is >> s; + assert(!is.eof()); + assert(!is.fail()); + assert(std::string((char*)s) == "abc"); + } +#endif { testbuf<char> sb(" abcdefghijk"); std::istream is(&sb); @@ -82,4 +93,15 @@ int main() assert(std::string((char*)s) == ""); assert(is.width() == 0); } +#if TEST_STD_VER > 17 + { + testbuf<char> sb(" abcdefghijk"); + std::istream is(&sb); + signed char s[1]; + is >> s; + assert(!is.eof()); + assert( is.fail()); + assert(std::string((char*)s) == ""); + } +#endif } diff --git a/libcxx/test/std/input.output/iostream.format/input.streams/istream.formatted/istream_extractors/unsigned_char_pointer.pass.cpp b/libcxx/test/std/input.output/iostream.format/input.streams/istream.formatted/istream_extractors/unsigned_char_pointer.pass.cpp index 07fa5a79e8f..1e98b7dfdbd 100644 --- a/libcxx/test/std/input.output/iostream.format/input.streams/istream.formatted/istream_extractors/unsigned_char_pointer.pass.cpp +++ b/libcxx/test/std/input.output/iostream.format/input.streams/istream.formatted/istream_extractors/unsigned_char_pointer.pass.cpp @@ -61,6 +61,17 @@ int main() assert(std::string((char*)s) == "abc"); assert(is.width() == 0); } +#if TEST_STD_VER > 17 + { + testbuf<char> sb(" abcdefghijk "); + std::istream is(&sb); + unsigned char s[4]; + is >> s; + assert(!is.eof()); + assert(!is.fail()); + assert(std::string((char*)s) == "abc"); + } +#endif { testbuf<char> sb(" abcdefghijk"); std::istream is(&sb); @@ -82,4 +93,15 @@ int main() assert(std::string((char*)s) == ""); assert(is.width() == 0); } +#if TEST_STD_VER > 17 + { + testbuf<char> sb(" abcdefghijk"); + std::istream is(&sb); + unsigned char s[1]; + is >> s; + assert(!is.eof()); + assert( is.fail()); + assert(std::string((char*)s) == ""); + } +#endif } diff --git a/libcxx/test/std/input.output/iostream.format/input.streams/istream.formatted/istream_extractors/wchar_t_pointer.pass.cpp b/libcxx/test/std/input.output/iostream.format/input.streams/istream.formatted/istream_extractors/wchar_t_pointer.pass.cpp index a00c7a1dda3..82e460db927 100644 --- a/libcxx/test/std/input.output/iostream.format/input.streams/istream.formatted/istream_extractors/wchar_t_pointer.pass.cpp +++ b/libcxx/test/std/input.output/iostream.format/input.streams/istream.formatted/istream_extractors/wchar_t_pointer.pass.cpp @@ -50,6 +50,17 @@ int main() assert(!is.fail()); assert(std::string(s) == "abcdefghijk"); } +#if TEST_STD_VER > 17 + { + testbuf<char> sb(" abcdefghijk "); + std::istream is(&sb); + char s[4]; + is >> s; + assert(!is.eof()); + assert(!is.fail()); + assert(std::string(s) == "abc"); + } +#endif { testbuf<wchar_t> sb(L" abcdefghijk "); std::wistream is(&sb); @@ -71,6 +82,17 @@ int main() assert(std::wstring(s) == L"abcdefghijk"); assert(is.width() == 0); } +#if TEST_STD_VER > 17 + { + testbuf<wchar_t> sb(L" abcdefghijk"); + std::wistream is(&sb); + wchar_t s[4]; + is >> s; + assert(!is.eof()); + assert(!is.fail()); + assert(std::wstring(s) == L"abc"); + } +#endif { testbuf<char> sb(" abcdefghijk"); std::istream is(&sb); @@ -82,4 +104,15 @@ int main() assert(std::string(s) == ""); assert(is.width() == 0); } +#if TEST_STD_VER > 17 + { + testbuf<char> sb(" abcdefghijk"); + std::istream is(&sb); + char s[1]; + is >> s; + assert(!is.eof()); + assert( is.fail()); + assert(std::string(s) == ""); + } +#endif } diff --git a/libcxx/www/cxx2a_status.html b/libcxx/www/cxx2a_status.html index 6ad48acef74..7c8c8319597 100644 --- a/libcxx/www/cxx2a_status.html +++ b/libcxx/www/cxx2a_status.html @@ -112,7 +112,7 @@ <tr><td><a href="https://wg21.link/P0356R5">P0356R5</a></td><td>LWG</td><td>Simplified partial function application</td><td>San Diego</td><td><i> </i></td><td></td></tr> <tr><td><a href="https://wg21.link/P0357R3">P0357R3</a></td><td>LWG</td><td>reference_wrapper for incomplete types</td><td>San Diego</td><td><i> </i></td><td></td></tr> <tr><td><a href="https://wg21.link/P0482R6">P0482R6</a></td><td>CWG</td><td>char8_t: A type for UTF-8 characters and strings</td><td>San Diego</td><td><i> </i></td><td></td></tr> - <tr><td><a href="https://wg21.link/P0487R1">P0487R1</a></td><td>LWG</td><td>Fixing operator>>(basic_istream&, CharT*) (LWG 2499)</td><td>San Diego</td><td><i> </i></td><td></td></tr> + <tr><td><a href="https://wg21.link/P0487R1">P0487R1</a></td><td>LWG</td><td>Fixing operator>>(basic_istream&, CharT*) (LWG 2499)</td><td>San Diego</td><td>Complete</td><td>8.0</td></tr> <tr><td><a href="https://wg21.link/P0591R4">P0591R4</a></td><td>LWG</td><td>Utility functions to implement uses-allocator construction</td><td>San Diego</td><td><i> </i></td><td></td></tr> <tr><td><a href="https://wg21.link/P0595R2">P0595R2</a></td><td>CWG</td><td>P0595R2 std::is_constant_evaluated()</td><td>San Diego</td><td><i> </i></td><td></td></tr> <tr><td><a href="https://wg21.link/P0602R4">P0602R4</a></td><td>LWG</td><td>variant and optional should propagate copy/move triviality</td><td>San Diego</td><td><i> </i></td><td></td></tr> |

