Skip to content

Commit ed962a6

Browse files
authored
[libc++] Implement LWG4023 (#87513)
This patch implements LWG4023 by adding explicit assertions for the added preconditions and also fixes a few tests that were violating these preconditions.
1 parent 182f5e9 commit ed962a6

File tree

7 files changed

+156
-19
lines changed

7 files changed

+156
-19
lines changed

libcxx/docs/Status/Cxx2cIssues.csv

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@
4949
"`4012 <https://wg21.link/LWG4012>`__","``common_view::begin/end`` are missing the ``simple-view`` check","Tokyo March 2024","","","|ranges|"
5050
"`4013 <https://wg21.link/LWG4013>`__","``lazy_split_view::outer-iterator::value_type`` should not provide default constructor","Tokyo March 2024","","","|ranges|"
5151
"`4016 <https://wg21.link/LWG4016>`__","container-insertable checks do not match what container-inserter does","Tokyo March 2024","","",""
52-
"`4023 <https://wg21.link/LWG4023>`__","Preconditions of ``std::basic_streambuf::setg/setp``","Tokyo March 2024","","",""
52+
"`4023 <https://wg21.link/LWG4023>`__","Preconditions of ``std::basic_streambuf::setg/setp``","Tokyo March 2024","|Complete|","19.0",""
5353
"`4025 <https://wg21.link/LWG4025>`__","Move assignment operator of ``std::expected<cv void, E>`` should not be conditionally deleted","Tokyo March 2024","","",""
5454
"`4030 <https://wg21.link/LWG4030>`__","Clarify whether arithmetic expressions in ``[numeric.sat.func]`` are mathematical or C++","Tokyo March 2024","|Nothing To Do|","",""
5555
"`4031 <https://wg21.link/LWG4031>`__","``bad_expected_access<void>`` member functions should be ``noexcept``","Tokyo March 2024","|Complete|","16.0",""

libcxx/include/streambuf

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,10 +107,12 @@ protected:
107107
108108
*/
109109

110+
#include <__assert>
110111
#include <__config>
111112
#include <__fwd/streambuf.h>
112113
#include <__locale>
113114
#include <__type_traits/is_same.h>
115+
#include <__utility/is_valid_range.h>
114116
#include <climits>
115117
#include <ios>
116118
#include <iosfwd>
@@ -234,6 +236,9 @@ protected:
234236
inline _LIBCPP_HIDE_FROM_ABI_AFTER_V1 void gbump(int __n) { __ninp_ += __n; }
235237

236238
inline _LIBCPP_HIDE_FROM_ABI_AFTER_V1 void setg(char_type* __gbeg, char_type* __gnext, char_type* __gend) {
239+
_LIBCPP_ASSERT_VALID_INPUT_RANGE(std::__is_valid_range(__gbeg, __gnext), "[gbeg, gnext) must be a valid range");
240+
_LIBCPP_ASSERT_VALID_INPUT_RANGE(std::__is_valid_range(__gbeg, __gend), "[gbeg, gend) must be a valid range");
241+
_LIBCPP_ASSERT_VALID_INPUT_RANGE(std::__is_valid_range(__gnext, __gend), "[gnext, gend) must be a valid range");
237242
__binp_ = __gbeg;
238243
__ninp_ = __gnext;
239244
__einp_ = __gend;
@@ -249,6 +254,7 @@ protected:
249254
_LIBCPP_HIDE_FROM_ABI void __pbump(streamsize __n) { __nout_ += __n; }
250255

251256
inline _LIBCPP_HIDE_FROM_ABI_AFTER_V1 void setp(char_type* __pbeg, char_type* __pend) {
257+
_LIBCPP_ASSERT_VALID_INPUT_RANGE(std::__is_valid_range(__pbeg, __pend), "[pbeg, pend) must be a valid range");
252258
__bout_ = __nout_ = __pbeg;
253259
__eout_ = __pend;
254260
}

libcxx/test/std/input.output/stream.buffers/streambuf/streambuf.cons/copy.pass.cpp

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -57,18 +57,20 @@ int main(int, char**)
5757
test<char> t2 = t;
5858
}
5959
{
60-
char g1, g2, g3, p1, p3;
60+
char g[3];
61+
char p[3];
6162
test<char> t;
62-
t.setg(&g1, &g2, &g3);
63-
t.setp(&p1, &p3);
63+
t.setg(&g[0], &g[1], &g[2]);
64+
t.setp(&p[0], &p[2]);
6465
test<char> t2 = t;
6566
}
6667
#ifndef TEST_HAS_NO_WIDE_CHARACTERS
6768
{
68-
wchar_t g1, g2, g3, p1, p3;
69+
wchar_t g[3];
70+
wchar_t p[3];
6971
test<wchar_t> t;
70-
t.setg(&g1, &g2, &g3);
71-
t.setp(&p1, &p3);
72+
t.setg(&g[0], &g[1], &g[2]);
73+
t.setp(&p[0], &p[2]);
7274
test<wchar_t> t2 = t;
7375
}
7476
{

libcxx/test/std/input.output/stream.buffers/streambuf/streambuf.protected/streambuf.assign/assign.pass.cpp

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -59,10 +59,11 @@ int main(int, char**)
5959
t2 = t;
6060
}
6161
{
62-
char g1, g2, g3, p1, p3;
62+
char g[3];
63+
char p[3];
6364
test<char> t;
64-
t.setg(&g1, &g2, &g3);
65-
t.setp(&p1, &p3);
65+
t.setg(&g[0], &g[1], &g[2]);
66+
t.setp(&p[0], &p[2]);
6667
test<char> t2;
6768
t2 = t;
6869
}
@@ -73,10 +74,11 @@ int main(int, char**)
7374
t2 = t;
7475
}
7576
{
76-
wchar_t g1, g2, g3, p1, p3;
77+
wchar_t g[3];
78+
wchar_t p[3];
7779
test<wchar_t> t;
78-
t.setg(&g1, &g2, &g3);
79-
t.setp(&p1, &p3);
80+
t.setg(&g[0], &g[1], &g[2]);
81+
t.setp(&p[0], &p[2]);
8082
test<wchar_t> t2;
8183
t2 = t;
8284
}

libcxx/test/std/input.output/stream.buffers/streambuf/streambuf.protected/streambuf.assign/swap.pass.cpp

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -68,10 +68,11 @@ int main(int, char**)
6868
t2.swap(t);
6969
}
7070
{
71-
char g1, g2, g3, p1, p3;
71+
char g[3];
72+
char p[3];
7273
test<char> t;
73-
t.setg(&g1, &g2, &g3);
74-
t.setp(&p1, &p3);
74+
t.setg(&g[0], &g[1], &g[2]);
75+
t.setp(&p[0], &p[2]);
7576
test<char> t2;
7677
t2.swap(t);
7778
}
@@ -82,10 +83,11 @@ int main(int, char**)
8283
t2.swap(t);
8384
}
8485
{
85-
wchar_t g1, g2, g3, p1, p3;
86+
wchar_t g[3];
87+
wchar_t p[3];
8688
test<wchar_t> t;
87-
t.setg(&g1, &g2, &g3);
88-
t.setp(&p1, &p3);
89+
t.setg(&g[0], &g[1], &g[2]);
90+
t.setp(&p[0], &p[2]);
8991
test<wchar_t> t2;
9092
t2.swap(t);
9193
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
// REQUIRES: has-unix-headers
10+
// UNSUPPORTED: libcpp-hardening-mode=none
11+
// XFAIL: libcpp-hardening-mode=debug && availability-verbose_abort-missing
12+
13+
// <streambuf>
14+
15+
// template <class charT, class traits = char_traits<charT> >
16+
// class basic_streambuf;
17+
18+
// void setg(char_type* gbeg, char_type* gnext, char_type* gend);
19+
20+
#include <algorithm>
21+
#include <iterator>
22+
#include <streambuf>
23+
#include <string>
24+
25+
#include "check_assertion.h"
26+
#include "make_string.h"
27+
#include "test_macros.h"
28+
29+
template <class CharT>
30+
struct streambuf : public std::basic_streambuf<CharT> {
31+
typedef std::basic_streambuf<CharT> base;
32+
33+
streambuf() {}
34+
35+
void setg(CharT* gbeg, CharT* gnext, CharT* gend) { base::setg(gbeg, gnext, gend); }
36+
};
37+
38+
template <class CharT>
39+
void test() {
40+
std::basic_string<CharT> str = MAKE_STRING(CharT, "ABCDEF");
41+
CharT arr[6];
42+
std::copy(str.begin(), str.end(), arr);
43+
44+
{
45+
streambuf<CharT> buff;
46+
TEST_LIBCPP_ASSERT_FAILURE(
47+
buff.setg(std::begin(arr) + 1, std::begin(arr), std::end(arr)), "[gbeg, gnext) must be a valid range");
48+
}
49+
{
50+
streambuf<CharT> buff;
51+
TEST_LIBCPP_ASSERT_FAILURE(
52+
buff.setg(std::begin(arr) + 1, std::begin(arr) + 1, std::begin(arr)), "[gbeg, gend) must be a valid range");
53+
}
54+
{
55+
streambuf<CharT> buff;
56+
TEST_LIBCPP_ASSERT_FAILURE(
57+
buff.setg(std::begin(arr), std::begin(arr) + 3, std::begin(arr) + 2), "[gnext, gend) must be a valid range");
58+
}
59+
}
60+
61+
int main(int, char**) {
62+
test<char>();
63+
#ifndef TEST_HAS_NO_WIDE_CHARACTERS
64+
test<wchar_t>();
65+
#endif
66+
67+
return 0;
68+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
// REQUIRES: has-unix-headers
10+
// UNSUPPORTED: libcpp-hardening-mode=none
11+
// XFAIL: libcpp-hardening-mode=debug && availability-verbose_abort-missing
12+
13+
// <streambuf>
14+
15+
// template <class charT, class traits = char_traits<charT> >
16+
// class basic_streambuf;
17+
18+
// void setp(char_type* pbeg, char_type* pend);
19+
20+
#include <algorithm>
21+
#include <iterator>
22+
#include <streambuf>
23+
#include <string>
24+
25+
#include "check_assertion.h"
26+
#include "make_string.h"
27+
#include "test_macros.h"
28+
29+
template <class CharT>
30+
struct streambuf : public std::basic_streambuf<CharT> {
31+
typedef std::basic_streambuf<CharT> base;
32+
33+
streambuf() {}
34+
35+
void setp(CharT* pbeg, CharT* pend) { base::setp(pbeg, pend); }
36+
};
37+
38+
template <class CharT>
39+
void test() {
40+
std::basic_string<CharT> str = MAKE_STRING(CharT, "ABCDEF");
41+
CharT arr[6];
42+
std::copy(str.begin(), str.end(), arr);
43+
44+
{
45+
streambuf<CharT> buff;
46+
TEST_LIBCPP_ASSERT_FAILURE(buff.setp(std::begin(arr) + 3, std::begin(arr)), "[pbeg, pend) must be a valid range");
47+
}
48+
}
49+
50+
int main(int, char**) {
51+
test<char>();
52+
#ifndef TEST_HAS_NO_WIDE_CHARACTERS
53+
test<wchar_t>();
54+
#endif
55+
56+
return 0;
57+
}

0 commit comments

Comments
 (0)