Skip to content

Commit beeb37a

Browse files
committed
[sanitizer] scanf interceptor: fix write size for %mc/%mC/%mS
When the optional assignment-allocation character 'm' (Extension to the ISO C standard) is present, we currently use internal_strlen(buf)+1 for all of cCsS[ (D85350). Fix cCS to use the correct size. Fix #61768 Reviewed By: #sanitizers, vitalybuka Differential Revision: https://reviews.llvm.org/D158485
1 parent 510b6b7 commit beeb37a

File tree

2 files changed

+37
-13
lines changed

2 files changed

+37
-13
lines changed

Diff for: compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors_format.inc

+12-4
Original file line numberDiff line numberDiff line change
@@ -340,11 +340,19 @@ static void scanf_common(void *ctx, int n_inputs, bool allowGnuMalloc,
340340
size = 0;
341341
}
342342
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, argp, size);
343-
// For %ms/%mc, write the allocated output buffer as well.
343+
// For %mc/%mC/%ms/%m[/%mS, write the allocated output buffer as well.
344344
if (dir.allocate) {
345-
char *buf = *(char **)argp;
346-
if (buf)
347-
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, internal_strlen(buf) + 1);
345+
if (char *buf = *(char **)argp) {
346+
if (dir.convSpecifier == 'c')
347+
size = 1;
348+
else if (dir.convSpecifier == 'C')
349+
size = sizeof(wchar_t);
350+
else if (dir.convSpecifier == 'S')
351+
size = (internal_wcslen((wchar_t *)buf) + 1) * sizeof(wchar_t);
352+
else // 's' or '['
353+
size = internal_strlen(buf) + 1;
354+
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, size);
355+
}
348356
}
349357
}
350358
}

Diff for: compiler-rt/lib/sanitizer_common/tests/sanitizer_format_interceptor_test.cpp

+25-9
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,16 @@
99
// Tests for *scanf interceptors implementation in sanitizer_common.
1010
//
1111
//===----------------------------------------------------------------------===//
12+
#include <wchar.h>
13+
1214
#include <algorithm>
1315
#include <vector>
1416

17+
#include "gtest/gtest.h"
1518
#include "interception/interception.h"
16-
#include "sanitizer_test_utils.h"
17-
#include "sanitizer_common/sanitizer_libc.h"
1819
#include "sanitizer_common/sanitizer_common.h"
19-
#include "gtest/gtest.h"
20+
#include "sanitizer_common/sanitizer_libc.h"
21+
#include "sanitizer_test_utils.h"
2022

2123
using namespace __sanitizer;
2224

@@ -206,21 +208,35 @@ TEST(SanitizerCommonInterceptors, Scanf) {
206208

207209
TEST(SanitizerCommonInterceptors, ScanfAllocate) {
208210
const char *buf = "123456";
211+
const wchar_t *wbuf = L"123";
209212

210213
// Can not use testScanf() because this case needs a valid pointer to a string
211214
// in the scanf argument.
215+
{
216+
std::vector<unsigned> scanf_sizes;
217+
testScanf3((void *)&scanf_sizes, 2, /*allowGnuMalloc=*/false, "%mc", &buf);
218+
verifyFormatResults("%mc", 2, scanf_sizes, {P, 1u});
219+
}
220+
{
221+
std::vector<unsigned> scanf_sizes;
222+
testScanf3((void *)&scanf_sizes, 2, /*allowGnuMalloc=*/false, "%mC", &wbuf);
223+
verifyFormatResults("%mC", 2, scanf_sizes, {P, (unsigned)sizeof(wchar_t)});
224+
}
212225
{
213226
std::vector<unsigned> scanf_sizes;
214227
testScanf3((void *)&scanf_sizes, 2, /*allowGnuMalloc=*/false, "%ms", &buf);
215-
verifyFormatResults("%ms", 2, scanf_sizes,
216-
{P, (unsigned)(strlen(buf) + 1)});
228+
verifyFormatResults("%ms", 2, scanf_sizes, {P, unsigned(strlen(buf) + 1)});
229+
scanf_sizes.clear();
230+
testScanf3((void *)&scanf_sizes, 2, /*allowGnuMalloc=*/false, "%m[0-9]",
231+
&buf);
232+
verifyFormatResults("%m[0-9]", 2, scanf_sizes,
233+
{P, unsigned(strlen(buf) + 1)});
217234
}
218-
219235
{
220236
std::vector<unsigned> scanf_sizes;
221-
testScanf3((void *)&scanf_sizes, 2, /*allowGnuMalloc=*/false, "%mc", &buf);
222-
verifyFormatResults("%mc", 2, scanf_sizes,
223-
{P, (unsigned)(strlen(buf) + 1)});
237+
testScanf3((void *)&scanf_sizes, 2, /*allowGnuMalloc=*/false, "%mS", &wbuf);
238+
verifyFormatResults("%mS", 2, scanf_sizes,
239+
{P, unsigned((wcslen(wbuf) + 1) * sizeof(wchar_t))});
224240
}
225241
}
226242

0 commit comments

Comments
 (0)