Skip to content

Commit 7eb1ae8

Browse files
committed
Handle SStream overflow by truncating appends
1 parent d4e5fa0 commit 7eb1ae8

3 files changed

Lines changed: 94 additions & 37 deletions

File tree

SStream.c

Lines changed: 56 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,47 @@
1818
#include "cs_priv.h"
1919
#include "utils.h"
2020

21+
static size_t SStream_remaining(SStream *ss)
22+
{
23+
assert(ss);
24+
if (ss->index >= SSTREAM_BUF_LEN) {
25+
ss->index = SSTREAM_BUF_LEN - 1;
26+
ss->buffer[ss->index] = '\0';
27+
return 0;
28+
}
29+
return SSTREAM_BUF_LEN - ss->index - 1;
30+
}
31+
32+
static void SStream_concat_raw(SStream *ss, const char *s, size_t len)
33+
{
34+
size_t remaining = SStream_remaining(ss);
35+
if (len > remaining) {
36+
len = remaining;
37+
}
38+
if (len > 0) {
39+
memcpy(ss->buffer + ss->index, s, len);
40+
ss->index += len;
41+
}
42+
ss->buffer[ss->index] = '\0';
43+
}
44+
45+
static void SStream_concat1_raw(SStream *ss, char c)
46+
{
47+
if (SStream_remaining(ss) == 0) {
48+
return;
49+
}
50+
ss->buffer[ss->index] = c;
51+
ss->index++;
52+
ss->buffer[ss->index] = '\0';
53+
}
54+
55+
static void SStream_close_markup(SStream *ss)
56+
{
57+
if (ss->markup_stream && ss->prefixed_by_markup) {
58+
SStream_concat1_raw(ss, '>');
59+
}
60+
}
61+
2162
void SStream_Init(SStream *ss)
2263
{
2364
assert(ss);
@@ -177,19 +218,9 @@ void SStream_concat0(SStream *ss, const char *s)
177218
SSTREAM_RETURN_IF_CLOSED(ss);
178219
if (s[0] == '\0')
179220
return;
180-
unsigned int len = (unsigned int)strlen(s);
181-
182-
SSTREAM_OVERFLOW_CHECK(ss, len);
183221

184-
memcpy(ss->buffer + ss->index, s, len);
185-
ss->index += len;
186-
ss->buffer[ss->index] = '\0';
187-
if (ss->markup_stream && ss->prefixed_by_markup) {
188-
SSTREAM_OVERFLOW_CHECK(ss, 1);
189-
ss->buffer[ss->index] = '>';
190-
ss->index += 1;
191-
ss->buffer[ss->index] = '\0';
192-
}
222+
SStream_concat_raw(ss, s, strlen(s));
223+
SStream_close_markup(ss);
193224
#else
194225
ss->buffer[ss->index] = '\0';
195226
#endif
@@ -206,16 +237,8 @@ void SStream_concat1(SStream *ss, const char c)
206237
if (c == '\0')
207238
return;
208239

209-
SSTREAM_OVERFLOW_CHECK(ss, 1);
210-
211-
ss->buffer[ss->index] = c;
212-
ss->index++;
213-
ss->buffer[ss->index] = '\0';
214-
if (ss->markup_stream && ss->prefixed_by_markup) {
215-
SSTREAM_OVERFLOW_CHECK(ss, 1);
216-
ss->buffer[ss->index] = '>';
217-
ss->index++;
218-
}
240+
SStream_concat1_raw(ss, c);
241+
SStream_close_markup(ss);
219242
#else
220243
ss->buffer[ss->index] = '\0';
221244
#endif
@@ -231,21 +254,25 @@ void SStream_concat(SStream *ss, const char *fmt, ...)
231254
SSTREAM_RETURN_IF_CLOSED(ss);
232255
va_list ap;
233256
int ret;
257+
size_t remaining = SStream_remaining(ss);
258+
if (remaining == 0) {
259+
return;
260+
}
234261

235262
va_start(ap, fmt);
236263
ret = cs_vsnprintf(ss->buffer + ss->index,
237-
sizeof(ss->buffer) - (ss->index + 1), fmt, ap);
264+
remaining + 1, fmt, ap);
238265
va_end(ap);
239266
if (ret < 0) {
267+
ss->buffer[ss->index] = '\0';
240268
return;
241269
}
242-
SSTREAM_OVERFLOW_CHECK(ss, ret);
243-
ss->index += ret;
244-
if (ss->markup_stream && ss->prefixed_by_markup) {
245-
SSTREAM_OVERFLOW_CHECK(ss, 1);
246-
ss->buffer[ss->index] = '>';
247-
ss->index += 1;
270+
if ((size_t)ret > remaining) {
271+
ss->index += remaining;
272+
} else {
273+
ss->index += (size_t)ret;
248274
}
275+
SStream_close_markup(ss);
249276
#else
250277
ss->buffer[ss->index] = '\0';
251278
#endif

SStream.h

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -25,14 +25,6 @@ typedef struct SStream {
2525
bool unsigned_num; ///< Print all numbers as unsigned. Set with CS_OPT_UNSIGNED.
2626
} SStream;
2727

28-
#define SSTREAM_OVERFLOW_CHECK(OS, len) \
29-
do { \
30-
if (OS->index + len + 1 > SSTREAM_BUF_LEN) { \
31-
fprintf(stderr, "Buffer overflow caught!\n"); \
32-
return; \
33-
} \
34-
} while (0)
35-
3628
#define SSTREAM_RETURN_IF_CLOSED(OS) \
3729
do { \
3830
if (OS->is_closed) \

tests/unit/sstream.c

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,43 @@ static bool test_overflow_check()
5959
return true;
6060
}
6161

62+
static bool test_truncating_appends()
63+
{
64+
printf("Test test_truncating_appends\n");
65+
66+
char too_long[SSTREAM_BUF_LEN + 1] = { 0 };
67+
memset(too_long, 'A', SSTREAM_BUF_LEN);
68+
char full[SSTREAM_BUF_LEN] = { 0 };
69+
memset(full, 'A', sizeof(full) - 1);
70+
71+
SStream OS = { 0 };
72+
SStream_Init(&OS);
73+
SStream_concat0(&OS, too_long);
74+
CHECK_OS_EQUAL_RET_FALSE(OS, full);
75+
CHECK_INT_EQUAL_RET_FALSE(OS.index, SSTREAM_BUF_LEN - 1);
76+
SStream_concat0(&OS, "B");
77+
CHECK_OS_EQUAL_RET_FALSE(OS, full);
78+
CHECK_INT_EQUAL_RET_FALSE(OS.index, SSTREAM_BUF_LEN - 1);
79+
80+
SStream_Flush(&OS, NULL);
81+
SStream_concat(&OS, "%s", too_long);
82+
CHECK_OS_EQUAL_RET_FALSE(OS, full);
83+
CHECK_INT_EQUAL_RET_FALSE(OS.index, SSTREAM_BUF_LEN - 1);
84+
85+
char almost_full[SSTREAM_BUF_LEN] = { 0 };
86+
memset(almost_full, 'C', SSTREAM_BUF_LEN - 2);
87+
SStream_Flush(&OS, NULL);
88+
SStream_concat0(&OS, almost_full);
89+
SStream_concat1(&OS, 'D');
90+
almost_full[SSTREAM_BUF_LEN - 2] = 'D';
91+
CHECK_OS_EQUAL_RET_FALSE(OS, almost_full);
92+
CHECK_INT_EQUAL_RET_FALSE(OS.index, SSTREAM_BUF_LEN - 1);
93+
SStream_concat1(&OS, 'E');
94+
CHECK_OS_EQUAL_RET_FALSE(OS, almost_full);
95+
CHECK_INT_EQUAL_RET_FALSE(OS.index, SSTREAM_BUF_LEN - 1);
96+
return true;
97+
}
98+
6299
static bool test_markup_os()
63100
{
64101
printf("Test test_markup_os\n");
@@ -670,6 +707,7 @@ int main()
670707
bool result = true;
671708
result &= test_markup_os();
672709
result &= test_overflow_check();
710+
result &= test_truncating_appends();
673711
result &= test_printint8();
674712
result &= test_printint16();
675713
result &= test_printint32();

0 commit comments

Comments
 (0)