summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/sanitizer_common/sanitizer_common_interceptors_format.inc68
-rw-r--r--lib/sanitizer_common/tests/sanitizer_format_interceptor_test.cc7
2 files changed, 43 insertions, 32 deletions
diff --git a/lib/sanitizer_common/sanitizer_common_interceptors_format.inc b/lib/sanitizer_common/sanitizer_common_interceptors_format.inc
index f7b085437..a2ce88944 100644
--- a/lib/sanitizer_common/sanitizer_common_interceptors_format.inc
+++ b/lib/sanitizer_common/sanitizer_common_interceptors_format.inc
@@ -80,24 +80,23 @@ static bool format_is_float_conv(char c) {
static int format_get_char_size(char convSpecifier,
const char lengthModifier[2]) {
if (char_is_one_of(convSpecifier, "CS")) {
- // wchar_t
- return 0;
+ return sizeof(wchar_t);
}
if (char_is_one_of(convSpecifier, "cs[")) {
- if (lengthModifier[0] == 'l')
- // wchar_t
- return 0;
- else if (lengthModifier[0] == 0)
+ if (lengthModifier[0] == 'l' && lengthModifier[1] == '\0')
+ return sizeof(wchar_t);
+ else if (lengthModifier[0] == '\0')
return sizeof(char);
- else
- return 0;
}
return 0;
}
enum FormatStoreSize {
+ // Store size not known in advance; can be calculated as wcslen() of the
+ // destination buffer.
+ FSS_WCSLEN = -2,
// Store size not known in advance; can be calculated as strlen() of the
// destination buffer.
FSS_STRLEN = -1,
@@ -108,7 +107,7 @@ enum FormatStoreSize {
// Returns the memory size of a format directive (if >0), or a value of
// FormatStoreSize.
static int format_get_value_size(char convSpecifier,
- const char lengthModifier[2], int fieldWidth,
+ const char lengthModifier[2],
bool promote_float) {
if (format_is_integer_conv(convSpecifier)) {
switch (lengthModifier[0]) {
@@ -149,15 +148,6 @@ static int format_get_value_size(char convSpecifier,
}
}
- if (char_is_one_of(convSpecifier, "cC")) {
- unsigned charSize = format_get_char_size(convSpecifier, lengthModifier);
- if (charSize == 0)
- return FSS_INVALID;
- if (fieldWidth == 0)
- return charSize;
- return fieldWidth * charSize;
- }
-
if (convSpecifier == 'p') {
if (lengthModifier[0] != 0)
return FSS_INVALID;
@@ -288,18 +278,21 @@ static int scanf_get_value_size(ScanfDirective *dir) {
return sizeof(char *) < sizeof(float) ? sizeof(char *) : sizeof(float);
}
- if (char_is_one_of(dir->convSpecifier, "sS[")) {
- unsigned charSize = format_get_char_size(dir->convSpecifier,
- dir->lengthModifier);
+ if (char_is_one_of(dir->convSpecifier, "cCsS[")) {
+ bool needsTerminator = char_is_one_of(dir->convSpecifier, "sS[");
+ unsigned charSize =
+ format_get_char_size(dir->convSpecifier, dir->lengthModifier);
if (charSize == 0)
return FSS_INVALID;
- if (dir->fieldWidth == 0)
- return FSS_STRLEN;
- return (dir->fieldWidth + 1) * charSize;
+ if (dir->fieldWidth == 0) {
+ if (!needsTerminator)
+ return charSize;
+ return (charSize == sizeof(char)) ? FSS_STRLEN : FSS_WCSLEN;
+ }
+ return (dir->fieldWidth + needsTerminator) * charSize;
}
- return format_get_value_size(dir->convSpecifier, dir->lengthModifier,
- dir->fieldWidth, false);
+ return format_get_value_size(dir->convSpecifier, dir->lengthModifier, false);
}
// Common part of *scanf interceptors.
@@ -342,6 +335,9 @@ static void scanf_common(void *ctx, int n_inputs, bool allowGnuMalloc,
break;
if (size == FSS_STRLEN) {
size = internal_strlen((const char *)argp) + 1;
+ } else if (size == FSS_WCSLEN) {
+ // FIXME: actually use wcslen() to calculate it.
+ size = 0;
}
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, argp, size);
}
@@ -442,16 +438,18 @@ static int printf_get_value_size(PrintfDirective *dir) {
return sizeof(char *);
}
- if (char_is_one_of(dir->convSpecifier, "sS")) {
- unsigned charSize = format_get_char_size(dir->convSpecifier,
- dir->lengthModifier);
+ if (char_is_one_of(dir->convSpecifier, "cCsS")) {
+ unsigned charSize =
+ format_get_char_size(dir->convSpecifier, dir->lengthModifier);
if (charSize == 0)
return FSS_INVALID;
- return FSS_STRLEN;
+ if (char_is_one_of(dir->convSpecifier, "sS")) {
+ return (charSize == sizeof(char)) ? FSS_STRLEN : FSS_WCSLEN;
+ }
+ return charSize;
}
- return format_get_value_size(dir->convSpecifier, dir->lengthModifier,
- dir->fieldWidth, true);
+ return format_get_value_size(dir->convSpecifier, dir->lengthModifier, true);
}
#define SKIP_SCALAR_ARG(aq, convSpecifier, size) \
@@ -542,6 +540,12 @@ static void printf_common(void *ctx, const char *format, va_list aq) {
}
COMMON_INTERCEPTOR_READ_RANGE(ctx, argp, size);
}
+ } else if (size == FSS_WCSLEN) {
+ if (void *argp = va_arg(aq, void *)) {
+ // FIXME: Properly support wide-character strings (via wcsrtombs).
+ size = 0;
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, argp, size);
+ }
} else {
// Skip non-pointer args
SKIP_SCALAR_ARG(&aq, dir.convSpecifier, size);
diff --git a/lib/sanitizer_common/tests/sanitizer_format_interceptor_test.cc b/lib/sanitizer_common/tests/sanitizer_format_interceptor_test.cc
index da2999591..4cfb95ddb 100644
--- a/lib/sanitizer_common/tests/sanitizer_format_interceptor_test.cc
+++ b/lib/sanitizer_common/tests/sanitizer_format_interceptor_test.cc
@@ -40,6 +40,7 @@ static const unsigned L = sizeof(long);
static const unsigned LL = sizeof(long long);
static const unsigned S = sizeof(short);
static const unsigned C = sizeof(char);
+static const unsigned LC = sizeof(wchar_t);
static const unsigned D = sizeof(double);
static const unsigned LD = sizeof(long double);
static const unsigned F = sizeof(float);
@@ -114,6 +115,7 @@ TEST(SanitizerCommonInterceptors, Scanf) {
testScanf("%qd", 1, LL);
testScanf("a %hd%hhx", 2, S, C);
testScanf("%c", 1, C);
+ testScanf("%lc", 1, LC);
testScanf("%%", 0);
testScanf("a%%", 0);
@@ -129,6 +131,8 @@ TEST(SanitizerCommonInterceptors, Scanf) {
testScanf("%10s", 1, 11);
testScanf("%10c", 1, 10);
+ testScanf("%10ls", 1, 11 * LC);
+ testScanf("%10lc", 1, 10 * LC);
testScanf("%%10s", 0);
testScanf("%*10s", 0);
testScanf("%*d", 0);
@@ -248,4 +252,7 @@ TEST(SanitizerCommonInterceptors, Printf) {
// Dynamic precision for strings is not implemented yet.
testPrintf("%.*s", 1, 0);
+
+ // Checks for wide-character strings are not implemented yet.
+ testPrintf("%ls", 1, 0);
}