Skip to content

Commit 94b0851

Browse files
committed
[sanitizer] use uptr to store the result of internal_strlen/internal_strnlen in printf_common
The return type of `internal_strlen()` is 'uptr', but in `printf_common()` we store the result of `internal_strlen()` into an 'int' type variable. When the result value of `internal_strlen()` is larger than the largest possible value of 'int' type, the implicit conversion from 'uptr' to 'int' will change the result value to a negative value. Without this change, asan reports a false positive negative-size-param in the added testcase. Reviewed By: vitalybuka Differential Revision: https://reviews.llvm.org/D157266
1 parent 04c1e52 commit 94b0851

File tree

2 files changed

+42
-7
lines changed

2 files changed

+42
-7
lines changed

compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors_format.inc

+8-7
Original file line numberDiff line numberDiff line change
@@ -547,24 +547,25 @@ static void printf_common(void *ctx, const char *format, va_list aq) {
547547
continue;
548548
} else if (size == FSS_STRLEN) {
549549
if (void *argp = va_arg(aq, void *)) {
550+
uptr len;
550551
if (dir.starredPrecision) {
551552
// FIXME: properly support starred precision for strings.
552-
size = 0;
553+
len = 0;
553554
} else if (dir.fieldPrecision > 0) {
554555
// Won't read more than "precision" symbols.
555-
size = internal_strnlen((const char *)argp, dir.fieldPrecision);
556-
if (size < dir.fieldPrecision) size++;
556+
len = internal_strnlen((const char *)argp, dir.fieldPrecision);
557+
if (len < (uptr)dir.fieldPrecision)
558+
len++;
557559
} else {
558560
// Whole string will be accessed.
559-
size = internal_strlen((const char *)argp) + 1;
561+
len = internal_strlen((const char *)argp) + 1;
560562
}
561-
COMMON_INTERCEPTOR_READ_RANGE(ctx, argp, size);
563+
COMMON_INTERCEPTOR_READ_RANGE(ctx, argp, len);
562564
}
563565
} else if (size == FSS_WCSLEN) {
564566
if (void *argp = va_arg(aq, void *)) {
565567
// FIXME: Properly support wide-character strings (via wcsrtombs).
566-
size = 0;
567-
COMMON_INTERCEPTOR_READ_RANGE(ctx, argp, size);
568+
COMMON_INTERCEPTOR_READ_RANGE(ctx, argp, 0);
568569
}
569570
} else {
570571
// Skip non-pointer args
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
// Test that the common part implementation of *printf interceptors does not
2+
// cause negative-size-param false positives.
3+
4+
// RUN: %clangxx -O2 %s -o %t
5+
// RUN: %env_tool_opts=check_printf=1 %run %t 2>&1
6+
7+
// FIXME: The maximum supported allocation size is too platform-specific:
8+
// REQUIRES: x86_64-target-arch
9+
10+
// FIXME: printf is not intercepted on Windows yet.
11+
// UNSUPPORTED: target={{.*windows-msvc.*}}
12+
13+
#include <stdarg.h>
14+
#include <stdio.h>
15+
#include <stdlib.h>
16+
#include <string.h>
17+
18+
void write(char *buf, int buf_size, const char *fmt, ...) {
19+
va_list args;
20+
va_start(args, fmt);
21+
vsnprintf(buf, buf_size, fmt, args);
22+
va_end(args);
23+
}
24+
25+
int main() {
26+
char buffer[100];
27+
const size_t kStrSize = 1UL << 31;
28+
char *x = (char *)malloc(kStrSize);
29+
memset(x, '=', kStrSize - 1);
30+
x[kStrSize - 1] = 0;
31+
write(buffer, 100, "%s\n", x);
32+
free(x);
33+
return 0;
34+
}

0 commit comments

Comments
 (0)