-
Notifications
You must be signed in to change notification settings - Fork 15.2k
[compiler-rt][asan] Add wcscpy/wcsncpy; enable wcscat/wcsncat on Windows #160493
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 1 commit
5c6dda8
205ece1
782669a
7279084
0127791
b8da91b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -65,6 +65,15 @@ static inline uptr MaybeRealStrnlen(const char *s, uptr maxlen) { | |
return internal_strnlen(s, maxlen); | ||
} | ||
|
||
static inline uptr MaybeRealWcsnlen(const wchar_t *s, uptr maxlen) { | ||
#if SANITIZER_INTERCEPT_WCSNLEN | ||
if (REAL(wcsnlen)) { | ||
return REAL(wcsnlen)(s, maxlen); | ||
} | ||
#endif | ||
return internal_wcsnlen(s, maxlen); | ||
} | ||
|
||
void SetThreadName(const char *name) { | ||
AsanThread *t = GetCurrentThread(); | ||
if (t) | ||
|
@@ -570,6 +579,20 @@ INTERCEPTOR(char *, strcpy, char *to, const char *from) { | |
return REAL(strcpy)(to, from); | ||
} | ||
|
||
INTERCEPTOR(wchar_t *, wcscpy, wchar_t *to, const wchar_t *from) { | ||
void *ctx; | ||
ASAN_INTERCEPTOR_ENTER(ctx, wcscpy); | ||
if (!TryAsanInitFromRtl()) | ||
return REAL(wcscpy)(to, from); | ||
if (flags()->replace_str) { | ||
uptr from_size = (internal_wcslen(from) + 1) * sizeof(wchar_t); | ||
|
||
CHECK_RANGES_OVERLAP("wcscpy", to, from_size, from, from_size); | ||
ASAN_READ_RANGE(ctx, from, from_size); | ||
ASAN_WRITE_RANGE(ctx, to, from_size); | ||
} | ||
return REAL(wcscpy)(to, from); | ||
} | ||
|
||
// Windows doesn't always define the strdup identifier, | ||
// and when it does it's a macro defined to either _strdup | ||
// or _strdup_dbg, _strdup_dbg ends up calling _strdup, so | ||
|
@@ -633,6 +656,20 @@ INTERCEPTOR(char*, strncpy, char *to, const char *from, usize size) { | |
return REAL(strncpy)(to, from, size); | ||
} | ||
|
||
INTERCEPTOR(wchar_t *, wcsncpy, wchar_t *to, const wchar_t *from, uptr size) { | ||
void *ctx; | ||
ASAN_INTERCEPTOR_ENTER(ctx, wcsncpy); | ||
AsanInitFromRtl(); | ||
if (flags()->replace_str) { | ||
uptr from_size = | ||
Min(size, MaybeRealWcsnlen(from, size) + 1) * sizeof(wchar_t); | ||
CHECK_RANGES_OVERLAP("wcsncpy", to, from_size, from, from_size); | ||
ASAN_READ_RANGE(ctx, from, from_size); | ||
ASAN_WRITE_RANGE(ctx, to, size * sizeof(wchar_t)); | ||
} | ||
return REAL(wcsncpy)(to, from, size); | ||
} | ||
|
||
template <typename Fn> | ||
static ALWAYS_INLINE auto StrtolImpl(void *ctx, Fn real, const char *nptr, | ||
char **endptr, int base) | ||
|
@@ -809,6 +846,11 @@ void InitializeAsanInterceptors() { | |
ASAN_INTERCEPT_FUNC(strncat); | ||
ASAN_INTERCEPT_FUNC(strncpy); | ||
ASAN_INTERCEPT_FUNC(strdup); | ||
|
||
// Intercept wcs* functions. | ||
ASAN_INTERCEPT_FUNC(wcscpy); | ||
ASAN_INTERCEPT_FUNC(wcsncpy); | ||
|
||
# if ASAN_INTERCEPT___STRDUP | ||
ASAN_INTERCEPT_FUNC(__strdup); | ||
#endif | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -551,7 +551,7 @@ SANITIZER_WEAK_IMPORT void *aligned_alloc(__sanitizer::usize __alignment, | |
#define SANITIZER_INTERCEPT_MALLOC_USABLE_SIZE (!SI_MAC && !SI_NETBSD) | ||
#define SANITIZER_INTERCEPT_MCHECK_MPROBE SI_LINUX_NOT_ANDROID | ||
#define SANITIZER_INTERCEPT_WCSLEN 1 | ||
#define SANITIZER_INTERCEPT_WCSCAT SI_POSIX | ||
#define SANITIZER_INTERCEPT_WCSCAT 1 | ||
|
||
#define SANITIZER_INTERCEPT_WCSDUP SI_POSIX | ||
#define SANITIZER_INTERCEPT_SIGNAL_AND_SIGACTION (!SI_WINDOWS && SI_NOT_FUCHSIA) | ||
#define SANITIZER_INTERCEPT_BSD_SIGNAL SI_ANDROID | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
// RUN: %clangxx_asan -O0 %s -o %t && not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK | ||
// RUN: %clangxx_asan -O1 %s -o %t && not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK | ||
// RUN: %clangxx_asan -O2 %s -o %t && not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK | ||
// RUN: %clangxx_asan -O3 %s -o %t && not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK | ||
|
||
#include <stdio.h> | ||
#include <wchar.h> | ||
|
||
int main() { | ||
wchar_t *start = L"X means "; | ||
wchar_t *append = L"dog"; | ||
wchar_t goodDst[12]; | ||
wcscpy(goodDst, start); | ||
wcscat(goodDst, append); | ||
|
||
wchar_t badDst[9]; | ||
wcscpy(badDst, start); | ||
printf("Good so far.\n"); | ||
// CHECK: Good so far. | ||
fflush(stdout); | ||
wcscat(badDst, append); // Boom! | ||
// CHECK: ERROR: AddressSanitizer: stack-buffer-overflow on address [[ADDR:0x[0-9a-f]+]] at pc {{0x[0-9a-f]+}} bp {{0x[0-9a-f]+}} sp {{0x[0-9a-f]+}} | ||
// CHECK: WRITE of size {{[0-9]+}} at [[ADDR:0x[0-9a-f]+]] thread T0 | ||
// CHECK: #0 [[ADDR:0x[0-9a-f]+]] in wcscat{{.*}}sanitizer_common_interceptors.inc:{{[0-9]+}} | ||
printf("Should have failed with ASAN error.\n"); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
// RUN: %clangxx_asan -O0 %s -o %t && not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK | ||
// RUN: %clangxx_asan -O1 %s -o %t && not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK | ||
// RUN: %clangxx_asan -O2 %s -o %t && not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK | ||
// RUN: %clangxx_asan -O3 %s -o %t && not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK | ||
|
||
#include <stdio.h> | ||
#include <wchar.h> | ||
|
||
int main() { | ||
wchar_t *src = L"X means dog"; | ||
wchar_t goodDst[12]; | ||
wcscpy(goodDst, src); | ||
|
||
wchar_t badDst[7]; | ||
printf("Good so far.\n"); | ||
// CHECK: Good so far. | ||
fflush(stdout); | ||
wcscpy(badDst, src); // Boom! | ||
// CHECK:ERROR: AddressSanitizer: stack-buffer-overflow on address [[ADDR:0x[0-9a-f]+]] at pc {{0x[0-9a-f]+}} bp {{0x[0-9a-f]+}} sp {{0x[0-9a-f]+}} | ||
// CHECK: WRITE of size {{[0-9]+}} at [[ADDR:0x[0-9a-f]+]] thread T0 | ||
// CHECK: #0 [[ADDR:0x[0-9a-f]+]] in wcscpy{{.*}}asan_interceptors.cpp:{{[0-9]+}} | ||
printf("Should have failed with ASAN error.\n"); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
// RUN: %clangxx_asan -O0 %s -o %t && not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK | ||
// RUN: %clangxx_asan -O1 %s -o %t && not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK | ||
// RUN: %clangxx_asan -O2 %s -o %t && not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK | ||
// RUN: %clangxx_asan -O3 %s -o %t && not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK | ||
|
||
#include <stdio.h> | ||
#include <wchar.h> | ||
|
||
int main() { | ||
wchar_t *start = L"X means "; | ||
wchar_t *append = L"dog"; | ||
wchar_t goodDst[15]; | ||
wcscpy(goodDst, start); | ||
wcsncat(goodDst, append, 5); | ||
|
||
wchar_t badDst[11]; | ||
wcscpy(badDst, start); | ||
wcsncat(badDst, append, 1); | ||
printf("Good so far.\n"); | ||
// CHECK: Good so far. | ||
fflush(stdout); | ||
wcsncat(badDst, append, 3); // Boom! | ||
// CHECK: ERROR: AddressSanitizer: stack-buffer-overflow on address [[ADDR:0x[0-9a-f]+]] at pc {{0x[0-9a-f]+}} bp {{0x[0-9a-f]+}} sp {{0x[0-9a-f]+}} | ||
// CHECK: WRITE of size {{[0-9]+}} at [[ADDR:0x[0-9a-f]+]] thread T0 | ||
// CHECK: #0 [[ADDR:0x[0-9a-f]+]] in wcsncat{{.*}}sanitizer_common_interceptors.inc:{{[0-9]+}} | ||
printf("Should have failed with ASAN error.\n"); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
// RUN: %clangxx_asan -O0 %s -o %t && not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK | ||
// RUN: %clangxx_asan -O1 %s -o %t && not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK | ||
// RUN: %clangxx_asan -O2 %s -o %t && not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK | ||
// RUN: %clangxx_asan -O3 %s -o %t && not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK | ||
|
||
#include <stdio.h> | ||
#include <wchar.h> | ||
|
||
int main() { | ||
wchar_t *src = L"X means dog"; | ||
wchar_t goodDst[12]; | ||
wcsncpy(goodDst, src, 12); | ||
|
||
wchar_t badDst[7]; | ||
wcsncpy(badDst, src, 7); // This should still work. | ||
printf("Good so far.\n"); | ||
// CHECK: Good so far. | ||
fflush(stdout); | ||
|
||
wcsncpy(badDst, src, 15); // Boom! | ||
// CHECK:ERROR: AddressSanitizer: stack-buffer-overflow on address [[ADDR:0x[0-9a-f]+]] at pc {{0x[0-9a-f]+}} bp {{0x[0-9a-f]+}} sp {{0x[0-9a-f]+}} | ||
// CHECK: WRITE of size {{[0-9]+}} at [[ADDR:0x[0-9a-f]+]] thread T0 | ||
// CHECK: #0 [[ADDR:0x[0-9a-f]+]] in wcsncpy{{.*}}asan_interceptors.cpp:{{[0-9]+}} | ||
printf("Should have failed with ASAN error.\n"); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please follow https://llvm.org/docs/CodingStandards.html#don-t-use-braces-on-simple-single-statement-bodies-of-if-else-loop-statements
(even though existing code, such as MaybeRealStrnlen() above, does not follow this convention)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done: removed braces in
MaybeRealWcsnlen()
and madeMaybeRealStrnlen()
consistent. Submitted as a fixup; will autosquash before landing. Thanks @thurstond.