Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/lib/libc/tests/stdio/flushlbuf_test.c
39530 views
1
/*-
2
* Copyright (c) 2023 Klara, Inc.
3
*
4
* SPDX-License-Identifier: BSD-2-Clause
5
*/
6
7
#include <errno.h>
8
#include <stdio.h>
9
10
#include <atf-c.h>
11
12
#define BUFSIZE 16
13
14
static const char seq[] =
15
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
16
"abcdefghijklmnopqrstuvwxyz"
17
"0123456789+/";
18
19
struct stream {
20
char buf[BUFSIZE];
21
unsigned int len;
22
unsigned int pos;
23
};
24
25
static int
26
writefn(void *cookie, const char *buf, int len)
27
{
28
struct stream *s = cookie;
29
int written = 0;
30
31
if (len <= 0)
32
return (0);
33
while (len > 0 && s->pos < s->len) {
34
s->buf[s->pos++] = *buf++;
35
written++;
36
len--;
37
}
38
if (written > 0)
39
return (written);
40
errno = EAGAIN;
41
return (-1);
42
}
43
44
ATF_TC_WITHOUT_HEAD(flushlbuf_partial);
45
ATF_TC_BODY(flushlbuf_partial, tc)
46
{
47
static struct stream s;
48
static char buf[BUFSIZE + 1];
49
FILE *f;
50
unsigned int i = 0;
51
int ret = 0;
52
53
/*
54
* Create the stream and its buffer, print just enough characters
55
* to the stream to fill the buffer without triggering a flush,
56
* then check the state.
57
*/
58
s.len = BUFSIZE / 2; // write will fail after this amount
59
ATF_REQUIRE((f = fwopen(&s, writefn)) != NULL);
60
ATF_REQUIRE(setvbuf(f, buf, _IOLBF, BUFSIZE) == 0);
61
while (i < BUFSIZE)
62
if ((ret = fprintf(f, "%c", seq[i++])) < 0)
63
break;
64
ATF_CHECK_EQ(BUFSIZE, i);
65
ATF_CHECK_EQ(seq[i - 1], buf[BUFSIZE - 1]);
66
ATF_CHECK_EQ(1, ret);
67
ATF_CHECK_EQ(0, s.pos);
68
69
/*
70
* At this point, the buffer is full but writefn() has not yet
71
* been called. The next fprintf() call will trigger a preemptive
72
* fflush(), and writefn() will consume s.len characters before
73
* returning EAGAIN, causing fprintf() to fail without having
74
* written anything (which is why we don't increment i here).
75
*/
76
ret = fprintf(f, "%c", seq[i]);
77
ATF_CHECK_ERRNO(EAGAIN, ret < 0);
78
ATF_CHECK_EQ(s.len, s.pos);
79
80
/*
81
* We have consumed s.len characters from the buffer, so continue
82
* printing until it is full again and check that no overflow has
83
* occurred yet.
84
*/
85
while (i < BUFSIZE + s.len)
86
fprintf(f, "%c", seq[i++]);
87
ATF_CHECK_EQ(BUFSIZE + s.len, i);
88
ATF_CHECK_EQ(seq[i - 1], buf[BUFSIZE - 1]);
89
ATF_CHECK_EQ(0, buf[BUFSIZE]);
90
91
/*
92
* The straw that breaks the camel's back: libc fails to recognize
93
* that the buffer is full and continues to write beyond its end.
94
*/
95
fprintf(f, "%c", seq[i++]);
96
ATF_CHECK_EQ(0, buf[BUFSIZE]);
97
}
98
99
ATF_TC_WITHOUT_HEAD(flushlbuf_full);
100
ATF_TC_BODY(flushlbuf_full, tc)
101
{
102
static struct stream s;
103
static char buf[BUFSIZE];
104
FILE *f;
105
unsigned int i = 0;
106
int ret = 0;
107
108
/*
109
* Create the stream and its buffer, print just enough characters
110
* to the stream to fill the buffer without triggering a flush,
111
* then check the state.
112
*/
113
s.len = 0; // any attempt to write will fail
114
ATF_REQUIRE((f = fwopen(&s, writefn)) != NULL);
115
ATF_REQUIRE(setvbuf(f, buf, _IOLBF, BUFSIZE) == 0);
116
while (i < BUFSIZE)
117
if ((ret = fprintf(f, "%c", seq[i++])) < 0)
118
break;
119
ATF_CHECK_EQ(BUFSIZE, i);
120
ATF_CHECK_EQ(seq[i - 1], buf[BUFSIZE - 1]);
121
ATF_CHECK_EQ(1, ret);
122
ATF_CHECK_EQ(0, s.pos);
123
124
/*
125
* At this point, the buffer is full but writefn() has not yet
126
* been called. The next fprintf() call will trigger a preemptive
127
* fflush(), and writefn() will immediately return EAGAIN, causing
128
* fprintf() to fail without having written anything (which is why
129
* we don't increment i here).
130
*/
131
ret = fprintf(f, "%c", seq[i]);
132
ATF_CHECK_ERRNO(EAGAIN, ret < 0);
133
ATF_CHECK_EQ(s.len, s.pos);
134
135
/*
136
* Now make our stream writeable.
137
*/
138
s.len = sizeof(s.buf);
139
140
/*
141
* Flush the stream again. The data we failed to write previously
142
* should still be in the buffer and will now be written to the
143
* stream.
144
*/
145
ATF_CHECK_EQ(0, fflush(f));
146
ATF_CHECK_EQ(seq[0], s.buf[0]);
147
}
148
149
ATF_TP_ADD_TCS(tp)
150
{
151
ATF_TP_ADD_TC(tp, flushlbuf_partial);
152
ATF_TP_ADD_TC(tp, flushlbuf_full);
153
154
return (atf_no_error());
155
}
156
157