summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--libstdc++-v3/include/std/istream31
-rw-r--r--libstdc++-v3/testsuite/27_io/basic_istream/extractors_character/char/pr106248.cc40
-rw-r--r--libstdc++-v3/testsuite/27_io/basic_istream/extractors_character/wchar_t/pr106248.cc40
3 files changed, 106 insertions, 5 deletions
diff --git a/libstdc++-v3/include/std/istream b/libstdc++-v3/include/std/istream
index b506c4f7504..416ef556fa1 100644
--- a/libstdc++-v3/include/std/istream
+++ b/libstdc++-v3/include/std/istream
@@ -784,7 +784,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
* - if `width()` is greater than zero, `n` is `min(width(), n)`
* - otherwise `n` is the number of elements of the array
* - (before C++20 the pointer is assumed to point to an array of
- * - the largest possible size for an array of `char_type`).
+ * the largest possible size for an array of `char_type`).
*
* Characters are extracted and stored until one of the following happens:
* - `n - 1` characters are stored
@@ -802,19 +802,40 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
inline basic_istream<_CharT, _Traits>&
operator>>(basic_istream<_CharT, _Traits>& __in, _CharT* __s)
{
+#ifdef __OPTIMIZE__
+ // Function inlining might make the buffer size known, allowing us to
+ // prevent overflow.
size_t __n = __builtin_object_size(__s, 0);
- if (__builtin_expect(__n < sizeof(_CharT), false))
+ if (__n < sizeof(_CharT))
{
// There is not even space for the required null terminator.
__glibcxx_assert(__n >= sizeof(_CharT));
+ // No point calling __istream_extract, but still need to reset width.
__in.width(0);
__in.setstate(ios_base::failbit);
}
+ else if (__n != (size_t)-1)
+ {
+ __n /= sizeof(_CharT);
+ streamsize __w = __in.width();
+ std::__istream_extract(__in, __s, __n);
+ if (__in.good() && (__w <= 0 || __n < __w))
+ {
+ // Stopped extracting early to avoid overflowing the buffer,
+ // but might have stopped anyway (and set eofbit) if at EOF.
+ const typename _Traits::int_type __c = __in.rdbuf()->sgetc();
+ const bool __eof = _Traits::eq_int_type(__c, _Traits::eof());
+ if (__builtin_expect(__eof, true)) // Assume EOF, not overflow.
+ __in.setstate(ios_base::eofbit);
+ }
+ }
else
+#endif // __OPTIMIZE
{
- if (__n == (size_t)-1)
- __n = __gnu_cxx::__numeric_traits<streamsize>::__max;
- std::__istream_extract(__in, __s, __n / sizeof(_CharT));
+ // Buffer size is unknown, have to assume it's huge.
+ streamsize __n = __gnu_cxx::__numeric_traits<streamsize>::__max;
+ __n /= sizeof(_CharT);
+ std::__istream_extract(__in, __s, __n);
}
return __in;
}
diff --git a/libstdc++-v3/testsuite/27_io/basic_istream/extractors_character/char/pr106248.cc b/libstdc++-v3/testsuite/27_io/basic_istream/extractors_character/char/pr106248.cc
new file mode 100644
index 00000000000..6d89a0e5fef
--- /dev/null
+++ b/libstdc++-v3/testsuite/27_io/basic_istream/extractors_character/char/pr106248.cc
@@ -0,0 +1,40 @@
+// { dg-do run }
+
+#include <sstream>
+#include <testsuite_hooks.h>
+
+void
+test_pr106248()
+{
+ char buf[5] = {'x', 'x', 'x', 'x', 'x'};
+ std::string s(" four");
+ std::istringstream in(s);
+ in >> buf;
+#if __cplusplus >= 202002L
+ // Extraction stops because buffer is full.
+ VERIFY( in.good() );
+#else
+ // PR libstdc++/106248
+ // Extraction stops because all input has been consumed and eofbit is set.
+ VERIFY( in.eof() );
+#endif
+ // Extracted string must be null-terminated.
+ VERIFY( buf[4] == '\0' );
+ VERIFY( std::string(buf) == "four" );
+
+ in.clear();
+ in.str(s);
+ for (int i = 0; i < 5; ++i)
+ s[i] = 'x';
+
+ in.width(5);
+ in >> buf;
+ // Extraction stops due to field width, eofbit not set.
+ VERIFY( in.good() );
+ VERIFY( std::string(buf) == "four" );
+}
+
+int main()
+{
+ test_pr106248();
+}
diff --git a/libstdc++-v3/testsuite/27_io/basic_istream/extractors_character/wchar_t/pr106248.cc b/libstdc++-v3/testsuite/27_io/basic_istream/extractors_character/wchar_t/pr106248.cc
new file mode 100644
index 00000000000..7c226600b9e
--- /dev/null
+++ b/libstdc++-v3/testsuite/27_io/basic_istream/extractors_character/wchar_t/pr106248.cc
@@ -0,0 +1,40 @@
+// { dg-do run }
+
+#include <sstream>
+#include <testsuite_hooks.h>
+
+void
+test_pr106248()
+{
+ wchar_t buf[5] = {L'x', L'x', L'x', L'x', L'x'};
+ std::wstring s(L" four");
+ std::wistringstream in(s);
+ in >> buf;
+#if __cplusplus >= 202002L
+ // Extraction stops because buffer is full.
+ VERIFY( in.good() );
+#else
+ // PR libstdc++/106248
+ // Extraction stops because all input has been consumed and eofbit is set.
+ VERIFY( in.eof() );
+#endif
+ // Extracted string must be null-terminated.
+ VERIFY( buf[4] == L'\0' );
+ VERIFY( std::wstring(buf) == L"four" );
+
+ in.clear();
+ in.str(s);
+ for (int i = 0; i < 5; ++i)
+ s[i] = L'x';
+
+ in.width(5);
+ in >> buf;
+ // Extraction stops due to field width, eofbit not set.
+ VERIFY( in.good() );
+ VERIFY( std::wstring(buf) == L"four" );
+}
+
+int main()
+{
+ test_pr106248();
+}