[libcxx-commits] [libcxx] [libc++] Fixes istream::sync. (PR #76467)

Mark de Wever via libcxx-commits libcxx-commits at lists.llvm.org
Tue Feb 13 11:09:55 PST 2024


https://github.com/mordante updated https://github.com/llvm/llvm-project/pull/76467

>From ade94f72bfcd69f8b6c1d121a9af00dfdd153b0b Mon Sep 17 00:00:00 2001
From: Mark de Wever <koraq at xs4all.nl>
Date: Wed, 27 Dec 2023 20:33:28 +0100
Subject: [PATCH 1/2] [libc++] Fixes istream::sync.

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
---
 libcxx/include/istream                        |  9 ++-
 .../istream.unformatted/sync.pass.cpp         | 75 ++++++++++++++++++-
 2 files changed, 79 insertions(+), 5 deletions(-)

diff --git a/libcxx/include/istream b/libcxx/include/istream
index 1c7fb992dff429..d030197a19c98b 100644
--- a/libcxx/include/istream
+++ b/libcxx/include/istream
@@ -1009,17 +1009,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 ec1195d6b32bd9..d25e6142bdd4b5 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,11 @@
 
 // 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.
+// UNSUPPORTED: using-built-library-before-llvm-19
+
 #include <istream>
 #include <cassert>
 
@@ -48,6 +53,18 @@ struct testbuf
     }
 };
 
+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 { };
 
@@ -85,21 +102,62 @@ struct throwing_testbuf
 
 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);
@@ -116,6 +174,21 @@ int main(int, char**)
         assert(threw);
     }
 #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);
@@ -131,7 +204,7 @@ int main(int, char**)
         assert( is.fail());
         assert(threw);
     }
-#endif
+#endif // TEST_HAS_NO_WIDE_CHARACTERS
 #endif // TEST_HAS_NO_EXCEPTIONS
 
     return 0;

>From 56814e5fa537c0ac6f02bc12ba81648a74085b99 Mon Sep 17 00:00:00 2001
From: Mark de Wever <zar-rpg at xs4all.nl>
Date: Tue, 13 Feb 2024 20:09:47 +0100
Subject: [PATCH 2/2] Update
 libcxx/test/std/input.output/iostream.format/input.streams/istream.unformatted/sync.pass.cpp

Co-authored-by: Louis Dionne <ldionne.2 at gmail.com>
---
 .../input.streams/istream.unformatted/sync.pass.cpp             | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

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 d25e6142bdd4b5..3608b99dea972c 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
@@ -13,7 +13,7 @@
 // The fix for bug 51497 and bug 51499 require and updated dylib due to
 // explicit instantiations. That means Apple backdeployment targets remain
 // broken.
-// UNSUPPORTED: using-built-library-before-llvm-19
+// XFAIL: using-built-library-before-llvm-19
 
 #include <istream>
 #include <cassert>



More information about the libcxx-commits mailing list