Skip to content

Commit 83e20ab

Browse files
committed
[libc++] Add internal checks for some basic_streambuf invariants
These invariants are always expected to hold, however it's not always clear that they do. Adding explicit checks for these invariants inside non-trivial functions of basic_streambuf makes that clear.
1 parent 4a509f8 commit 83e20ab

File tree

1 file changed

+40
-0
lines changed

1 file changed

+40
-0
lines changed

libcxx/include/streambuf

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,7 @@ protected:
119119
# include <__locale>
120120
# include <__type_traits/is_same.h>
121121
# include <__utility/is_valid_range.h>
122+
# include <__utility/scope_guard.h>
122123
# include <climits>
123124
# include <ios>
124125
# include <iosfwd>
@@ -178,18 +179,27 @@ public:
178179
// Get and put areas:
179180
// 27.6.2.2.3 Get area:
180181
inline _LIBCPP_HIDE_FROM_ABI_AFTER_V1 streamsize in_avail() {
182+
__check_invariants();
183+
auto __guard = std::__make_scope_guard([this] { this->__check_invariants(); });
184+
181185
if (gptr() < egptr())
182186
return static_cast<streamsize>(egptr() - gptr());
183187
return showmanyc();
184188
}
185189

186190
inline _LIBCPP_HIDE_FROM_ABI_AFTER_V1 int_type snextc() {
191+
__check_invariants();
192+
auto __guard = std::__make_scope_guard([this] { this->__check_invariants(); });
193+
187194
if (sbumpc() == traits_type::eof())
188195
return traits_type::eof();
189196
return sgetc();
190197
}
191198

192199
inline _LIBCPP_HIDE_FROM_ABI_AFTER_V1 int_type sbumpc() {
200+
__check_invariants();
201+
auto __guard = std::__make_scope_guard([this] { this->__check_invariants(); });
202+
193203
if (gptr() == egptr())
194204
return uflow();
195205
int_type __c = traits_type::to_int_type(*gptr());
@@ -198,6 +208,9 @@ public:
198208
}
199209

200210
inline _LIBCPP_HIDE_FROM_ABI_AFTER_V1 int_type sgetc() {
211+
__check_invariants();
212+
auto __guard = std::__make_scope_guard([this] { this->__check_invariants(); });
213+
201214
if (gptr() == egptr())
202215
return underflow();
203216
return traits_type::to_int_type(*gptr());
@@ -207,13 +220,19 @@ public:
207220

208221
// 27.6.2.2.4 Putback:
209222
inline _LIBCPP_HIDE_FROM_ABI_AFTER_V1 int_type sputbackc(char_type __c) {
223+
__check_invariants();
224+
auto __guard = std::__make_scope_guard([this] { this->__check_invariants(); });
225+
210226
if (eback() == gptr() || !traits_type::eq(__c, *(gptr() - 1)))
211227
return pbackfail(traits_type::to_int_type(__c));
212228
this->gbump(-1);
213229
return traits_type::to_int_type(*gptr());
214230
}
215231

216232
inline _LIBCPP_HIDE_FROM_ABI_AFTER_V1 int_type sungetc() {
233+
__check_invariants();
234+
auto __guard = std::__make_scope_guard([this] { this->__check_invariants(); });
235+
217236
if (eback() == gptr())
218237
return pbackfail();
219238
this->gbump(-1);
@@ -222,6 +241,9 @@ public:
222241

223242
// 27.6.2.2.5 Put area:
224243
inline _LIBCPP_HIDE_FROM_ABI_AFTER_V1 int_type sputc(char_type __c) {
244+
__check_invariants();
245+
auto __guard = std::__make_scope_guard([this] { this->__check_invariants(); });
246+
225247
if (pptr() == epptr())
226248
return overflow(traits_type::to_int_type(__c));
227249
*pptr() = __c;
@@ -317,6 +339,9 @@ protected:
317339
virtual streamsize showmanyc() { return 0; }
318340

319341
virtual streamsize xsgetn(char_type* __s, streamsize __n) {
342+
__check_invariants();
343+
auto __guard = std::__make_scope_guard([this] { this->__check_invariants(); });
344+
320345
int_type __c;
321346
streamsize __i = 0;
322347
while (__i < __n) {
@@ -338,6 +363,9 @@ protected:
338363

339364
virtual int_type underflow() { return traits_type::eof(); }
340365
virtual int_type uflow() {
366+
__check_invariants();
367+
auto __guard = std::__make_scope_guard([this] { this->__check_invariants(); });
368+
341369
if (underflow() == traits_type::eof())
342370
return traits_type::eof();
343371
int_type __c = traits_type::to_int_type(*gptr());
@@ -350,6 +378,9 @@ protected:
350378

351379
// 27.6.2.4.5 Put area:
352380
virtual streamsize xsputn(const char_type* __s, streamsize __n) {
381+
__check_invariants();
382+
auto __guard = std::__make_scope_guard([this] { this->__check_invariants(); });
383+
353384
streamsize __i = 0;
354385
while (__i < __n) {
355386
if (pptr() >= epptr()) {
@@ -370,6 +401,15 @@ protected:
370401

371402
virtual int_type overflow(int_type = traits_type::eof()) { return traits_type::eof(); }
372403

404+
// This function checks some invariants of the class (it isn't exhaustive).
405+
_LIBCPP_HIDE_FROM_ABI void __check_invariants() const {
406+
_LIBCPP_ASSERT_INTERNAL(pbase() <= pptr(), "this is an invariant of the class");
407+
_LIBCPP_ASSERT_INTERNAL(pptr() <= epptr(), "this is an invariant of the class");
408+
409+
_LIBCPP_ASSERT_INTERNAL(eback() <= gptr(), "this is an invariant of the class");
410+
_LIBCPP_ASSERT_INTERNAL(gptr() <= egptr(), "this is an invariant of the class");
411+
}
412+
373413
private:
374414
locale __loc_;
375415
char_type* __binp_ = nullptr;

0 commit comments

Comments
 (0)