summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMark de Wever <koraq@xs4all.nl>2024-02-18 17:20:49 +0100
committerGitHub <noreply@github.com>2024-02-18 17:20:49 +0100
commit54daf6af57fb15d7a51e3f4bb889199fd1453bee (patch)
treeb3c0ac7c43c3a52f7e703f4385bb723f8a9a4241
parent886294a2fe5928ecf34299e02526e17be19910c6 (diff)
[libc++] Fixes istream::sync. (#76467)
This fixes two issues. The return value ---------------- Based on the wording [istream.unformatted]/37 Effects: Behaves as an unformatted input function (as described above), except that it does not count the number of characters extracted and does not affect the value returned by subsequent calls to gcount(). After constructing a sentry object, if rdbuf() is a null pointer, returns -1. [istream.unformatted]/1 ... It then creates an object of class sentry with the default argument noskipws (second) argument true. If the sentry object returns true, when converted to a value of type bool, the function endeavors to obtain the requested input. ... It could be argued the current behaviour is correct, however constructing a istream rdbuf() == nullptr creates a sentry that returns false; its state is always bad in this case. As mentioned in the bug report, after this change the 3 major implementations behave the same. The setting of the state ------------------------ When pubsync returned -1 it updated the local __state variable and returned. This early return caused the state up the istream not to be updated to the new state. Fixes: https://github.com/llvm/llvm-project/issues/51497 Fixes: https://github.com/llvm/llvm-project/issues/51499 --------- Co-authored-by: Louis Dionne <ldionne.2@gmail.com>
-rw-r--r--libcxx/include/istream9
-rw-r--r--libcxx/test/std/input.output/iostream.format/input.streams/istream.unformatted/sync.pass.cpp76
2 files changed, 80 insertions, 5 deletions
diff --git a/libcxx/include/istream b/libcxx/include/istream
index 0d05a26091a4..7975a9e599a5 100644
--- a/libcxx/include/istream
+++ b/libcxx/include/istream
@@ -1010,17 +1010,18 @@ basic_istream<_CharT, _Traits>& basic_istream<_CharT, _Traits>::unget() {
template <class _CharT, class _Traits>
int basic_istream<_CharT, _Traits>::sync() {
ios_base::iostate __state = ios_base::goodbit;
- int __r = 0;
sentry __sen(*this, true);
+ if (this->rdbuf() == nullptr)
+ return -1;
+
+ int __r = 0;
if (__sen) {
#ifndef _LIBCPP_HAS_NO_EXCEPTIONS
try {
#endif // _LIBCPP_HAS_NO_EXCEPTIONS
- if (this->rdbuf() == nullptr)
- return -1;
if (this->rdbuf()->pubsync() == -1) {
__state |= ios_base::badbit;
- return -1;
+ __r = -1;
}
#ifndef _LIBCPP_HAS_NO_EXCEPTIONS
} catch (...) {
diff --git a/libcxx/test/std/input.output/iostream.format/input.streams/istream.unformatted/sync.pass.cpp b/libcxx/test/std/input.output/iostream.format/input.streams/istream.unformatted/sync.pass.cpp
index ec1195d6b32b..4fa58c0abfba 100644
--- a/libcxx/test/std/input.output/iostream.format/input.streams/istream.unformatted/sync.pass.cpp
+++ b/libcxx/test/std/input.output/iostream.format/input.streams/istream.unformatted/sync.pass.cpp
@@ -10,6 +10,12 @@
// int sync();
+// The fix for bug 51497 and bug 51499 require and updated dylib due to
+// explicit instantiations. That means Apple backdeployment targets remain
+// broken.
+// TODO(#82107) Enable XFAIL.
+// UNSUPPORTED: using-built-library-before-llvm-19
+
#include <istream>
#include <cassert>
@@ -48,6 +54,18 @@ protected:
}
};
+template <class CharT>
+struct testbuf_pubsync_error
+ : public std::basic_streambuf<CharT>
+{
+public:
+
+ testbuf_pubsync_error() {}
+protected:
+ virtual int sync() { return -1; }
+};
+
+
#ifndef TEST_HAS_NO_EXCEPTIONS
struct testbuf_exception { };
@@ -86,21 +104,62 @@ protected:
int main(int, char**)
{
{
+ std::istream is(nullptr);
+ assert(is.sync() == -1);
+ }
+ {
testbuf<char> sb(" 123456789");
std::istream is(&sb);
assert(is.sync() == 0);
assert(sync_called == 1);
}
+ {
+ testbuf_pubsync_error<char> sb;
+ std::istream is(&sb);
+ is.exceptions(std::ios_base::failbit | std::ios_base::eofbit);
+ assert(is.sync() == -1);
+ assert( is.bad());
+ assert(!is.eof());
+ assert( is.fail());
+ }
#ifndef TEST_HAS_NO_WIDE_CHARACTERS
{
+ std::wistream is(nullptr);
+ assert(is.sync() == -1);
+ }
+ {
testbuf<wchar_t> sb(L" 123456789");
std::wistream is(&sb);
assert(is.sync() == 0);
assert(sync_called == 2);
}
+ {
+ testbuf_pubsync_error<wchar_t> sb;
+ std::wistream is(&sb);
+ is.exceptions(std::ios_base::failbit | std::ios_base::eofbit);
+ assert(is.sync() == -1);
+ assert( is.bad());
+ assert(!is.eof());
+ assert( is.fail());
+ }
#endif
#ifndef TEST_HAS_NO_EXCEPTIONS
{
+ testbuf_pubsync_error<char> sb;
+ std::istream is(&sb);
+ is.exceptions(std::ios_base::badbit);
+ bool threw = false;
+ try {
+ is.sync();
+ } catch (std::ios_base::failure const&) {
+ threw = true;
+ }
+ assert( is.bad());
+ assert(!is.eof());
+ assert( is.fail());
+ assert(threw);
+ }
+ {
throwing_testbuf<char> sb(" 123456789");
std::basic_istream<char> is(&sb);
is.exceptions(std::ios_base::badbit);
@@ -117,6 +176,21 @@ int main(int, char**)
}
#ifndef TEST_HAS_NO_WIDE_CHARACTERS
{
+ testbuf_pubsync_error<wchar_t> sb;
+ std::wistream is(&sb);
+ is.exceptions(std::ios_base::badbit);
+ bool threw = false;
+ try {
+ is.sync();
+ } catch (std::ios_base::failure const&) {
+ threw = true;
+ }
+ assert( is.bad());
+ assert(!is.eof());
+ assert( is.fail());
+ assert(threw);
+ }
+ {
throwing_testbuf<wchar_t> sb(L" 123456789");
std::basic_istream<wchar_t> is(&sb);
is.exceptions(std::ios_base::badbit);
@@ -131,7 +205,7 @@ int main(int, char**)
assert( is.fail());
assert(threw);
}
-#endif
+#endif // TEST_HAS_NO_WIDE_CHARACTERS
#endif // TEST_HAS_NO_EXCEPTIONS
return 0;