Skip to content

Commit 54daf6a

Browse files
mordanteldionne
andauthored
[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: #51497 Fixes: #51499 --------- Co-authored-by: Louis Dionne <[email protected]>
1 parent 886294a commit 54daf6a

File tree

2 files changed

+80
-5
lines changed
  • libcxx

2 files changed

+80
-5
lines changed

libcxx/include/istream

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1010,17 +1010,18 @@ basic_istream<_CharT, _Traits>& basic_istream<_CharT, _Traits>::unget() {
10101010
template <class _CharT, class _Traits>
10111011
int basic_istream<_CharT, _Traits>::sync() {
10121012
ios_base::iostate __state = ios_base::goodbit;
1013-
int __r = 0;
10141013
sentry __sen(*this, true);
1014+
if (this->rdbuf() == nullptr)
1015+
return -1;
1016+
1017+
int __r = 0;
10151018
if (__sen) {
10161019
#ifndef _LIBCPP_HAS_NO_EXCEPTIONS
10171020
try {
10181021
#endif // _LIBCPP_HAS_NO_EXCEPTIONS
1019-
if (this->rdbuf() == nullptr)
1020-
return -1;
10211022
if (this->rdbuf()->pubsync() == -1) {
10221023
__state |= ios_base::badbit;
1023-
return -1;
1024+
__r = -1;
10241025
}
10251026
#ifndef _LIBCPP_HAS_NO_EXCEPTIONS
10261027
} catch (...) {

libcxx/test/std/input.output/iostream.format/input.streams/istream.unformatted/sync.pass.cpp

Lines changed: 75 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,12 @@
1010

1111
// int sync();
1212

13+
// The fix for bug 51497 and bug 51499 require and updated dylib due to
14+
// explicit instantiations. That means Apple backdeployment targets remain
15+
// broken.
16+
// TODO(#82107) Enable XFAIL.
17+
// UNSUPPORTED: using-built-library-before-llvm-19
18+
1319
#include <istream>
1420
#include <cassert>
1521

@@ -48,6 +54,18 @@ struct testbuf
4854
}
4955
};
5056

57+
template <class CharT>
58+
struct testbuf_pubsync_error
59+
: public std::basic_streambuf<CharT>
60+
{
61+
public:
62+
63+
testbuf_pubsync_error() {}
64+
protected:
65+
virtual int sync() { return -1; }
66+
};
67+
68+
5169
#ifndef TEST_HAS_NO_EXCEPTIONS
5270
struct testbuf_exception { };
5371

@@ -85,21 +103,62 @@ struct throwing_testbuf
85103

86104
int main(int, char**)
87105
{
106+
{
107+
std::istream is(nullptr);
108+
assert(is.sync() == -1);
109+
}
88110
{
89111
testbuf<char> sb(" 123456789");
90112
std::istream is(&sb);
91113
assert(is.sync() == 0);
92114
assert(sync_called == 1);
93115
}
116+
{
117+
testbuf_pubsync_error<char> sb;
118+
std::istream is(&sb);
119+
is.exceptions(std::ios_base::failbit | std::ios_base::eofbit);
120+
assert(is.sync() == -1);
121+
assert( is.bad());
122+
assert(!is.eof());
123+
assert( is.fail());
124+
}
94125
#ifndef TEST_HAS_NO_WIDE_CHARACTERS
126+
{
127+
std::wistream is(nullptr);
128+
assert(is.sync() == -1);
129+
}
95130
{
96131
testbuf<wchar_t> sb(L" 123456789");
97132
std::wistream is(&sb);
98133
assert(is.sync() == 0);
99134
assert(sync_called == 2);
100135
}
136+
{
137+
testbuf_pubsync_error<wchar_t> sb;
138+
std::wistream is(&sb);
139+
is.exceptions(std::ios_base::failbit | std::ios_base::eofbit);
140+
assert(is.sync() == -1);
141+
assert( is.bad());
142+
assert(!is.eof());
143+
assert( is.fail());
144+
}
101145
#endif
102146
#ifndef TEST_HAS_NO_EXCEPTIONS
147+
{
148+
testbuf_pubsync_error<char> sb;
149+
std::istream is(&sb);
150+
is.exceptions(std::ios_base::badbit);
151+
bool threw = false;
152+
try {
153+
is.sync();
154+
} catch (std::ios_base::failure const&) {
155+
threw = true;
156+
}
157+
assert( is.bad());
158+
assert(!is.eof());
159+
assert( is.fail());
160+
assert(threw);
161+
}
103162
{
104163
throwing_testbuf<char> sb(" 123456789");
105164
std::basic_istream<char> is(&sb);
@@ -116,6 +175,21 @@ int main(int, char**)
116175
assert(threw);
117176
}
118177
#ifndef TEST_HAS_NO_WIDE_CHARACTERS
178+
{
179+
testbuf_pubsync_error<wchar_t> sb;
180+
std::wistream is(&sb);
181+
is.exceptions(std::ios_base::badbit);
182+
bool threw = false;
183+
try {
184+
is.sync();
185+
} catch (std::ios_base::failure const&) {
186+
threw = true;
187+
}
188+
assert( is.bad());
189+
assert(!is.eof());
190+
assert( is.fail());
191+
assert(threw);
192+
}
119193
{
120194
throwing_testbuf<wchar_t> sb(L" 123456789");
121195
std::basic_istream<wchar_t> is(&sb);
@@ -131,7 +205,7 @@ int main(int, char**)
131205
assert( is.fail());
132206
assert(threw);
133207
}
134-
#endif
208+
#endif // TEST_HAS_NO_WIDE_CHARACTERS
135209
#endif // TEST_HAS_NO_EXCEPTIONS
136210

137211
return 0;

0 commit comments

Comments
 (0)