Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 43 additions & 0 deletions compiler-rt/lib/asan/asan_interceptors.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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_STRNLEN
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this supposed to be SANITIZER_INTERCEPT_WCSLEN? Or should there be a wide string equivalent?

if (REAL(wcsnlen)) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this code does not {} in cases like this

return REAL(wcsnlen)(s, maxlen);
}
# endif
return internal_wcsnlen(s, maxlen);
}

void SetThreadName(const char *name) {
AsanThread *t = GetCurrentThread();
if (t)
Expand Down Expand Up @@ -570,6 +579,21 @@ 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
Expand Down Expand Up @@ -630,6 +654,20 @@ INTERCEPTOR(char*, strncpy, char *to, const char *from, uptr 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, strncpy);
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);
}
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)
Expand Down Expand Up @@ -781,6 +819,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
Expand Down
1 change: 1 addition & 0 deletions compiler-rt/lib/asan/asan_interceptors.h
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,7 @@ DECLARE_REAL(char*, strchr, const char *str, int c)
DECLARE_REAL(SIZE_T, strlen, const char *s)
DECLARE_REAL(char*, strncpy, char *to, const char *from, uptr size)
DECLARE_REAL(uptr, strnlen, const char *s, uptr maxlen)
DECLARE_REAL(uptr, wcsnlen, const wchar_t *s, uptr maxlen)
DECLARE_REAL(char*, strstr, const char *s1, const char *s2)

# if !SANITIZER_APPLE
Expand Down
4 changes: 4 additions & 0 deletions compiler-rt/lib/asan/asan_win_dll_thunk.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,10 @@ INTERCEPT_LIBRARY_FUNCTION(strstr);
INTERCEPT_LIBRARY_FUNCTION(strtok);
INTERCEPT_LIBRARY_FUNCTION(strtol);
INTERCEPT_LIBRARY_FUNCTION(strtoll);
INTERCEPT_LIBRARY_FUNCTION(wcscat);
INTERCEPT_LIBRARY_FUNCTION(wcscpy);
INTERCEPT_LIBRARY_FUNCTION(wcsncat);
INTERCEPT_LIBRARY_FUNCTION(wcsncpy);
INTERCEPT_LIBRARY_FUNCTION(wcslen);
INTERCEPT_LIBRARY_FUNCTION(wcsnlen);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -498,7 +498,7 @@
#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
Expand Down
49 changes: 49 additions & 0 deletions compiler-rt/test/asan/TestCases/wcscat.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
// RUN: %clangxx_asan -O0 %s -o %t && not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-%os --check-prefix=CHECK
// RUN: %clangxx_asan -O1 %s -o %t && not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-%os --check-prefix=CHECK
// RUN: %clangxx_asan -O2 %s -o %t && not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-%os --check-prefix=CHECK
// RUN: %clangxx_asan -O3 %s -o %t && not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-%os --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.
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]+}}
// CHECK: #1 [[ADDR:0x[0-9a-f]+]] in main {{.*}}\TestCases\wcscat.cpp:22
// CHECK: This frame has 2 object(s):
// CHECK: HINT: this may be a false positive if your program uses some custom stack unwind mechanism, swapcontext or vfork
// CHECK: (longjmp, SEH and C++ exceptions *are* supported)
// CHECK: SUMMARY: AddressSanitizer: stack-buffer-overflow {{.*}} in main
// CHECK: Shadow bytes around the buggy address:
// CHECK: Shadow byte legend (one shadow byte represents 8 application bytes):
// CHECK-NEXT: Addressable: 00
// CHECK-NEXT: Partially addressable: 01 02 03 04 05 06 07
// CHECK-NEXT: Heap left redzone: fa
// CHECK-NEXT: Freed heap region: fd
// CHECK-NEXT: Stack left redzone: f1
// CHECK-NEXT: Stack mid redzone: f2
// CHECK-NEXT: Stack right redzone: f3
// CHECK-NEXT: Stack after return: f5
// CHECK-NEXT: Stack use after scope: f8
// CHECK-NEXT: Global redzone: f9
// CHECK-NEXT: Global init order: f6
// CHECK-NEXT: Poisoned by user: f7
// CHECK-NEXT: Container overflow: fc
// CHECK-NEXT: Array cookie: ac
// CHECK-NEXT: Intra object redzone: bb
// CHECK-NEXT: ASan internal: fe
// CHECK-NEXT: Left alloca redzone: ca
// CHECK-NEXT: Right alloca redzone: cb
}
48 changes: 48 additions & 0 deletions compiler-rt/test/asan/TestCases/wcscpy.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
// RUN: %clangxx_asan -O0 %s -o %t && not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-%os --check-prefix=CHECK
// RUN: %clangxx_asan -O1 %s -o %t && not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-%os --check-prefix=CHECK
// RUN: %clangxx_asan -O2 %s -o %t && not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-%os --check-prefix=CHECK
// RUN: %clangxx_asan -O3 %s -o %t && not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-%os --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.

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]+}}
// CHECK: #1 [[ADDR:0x[0-9a-f]+]] in main {{.*}}\TestCases\wcscpy.cpp:20
// CHECK: This frame has 2 object(s):
// CHECK: HINT: this may be a false positive if your program uses some custom stack unwind mechanism, swapcontext or vfork
// CHECK: (longjmp, SEH and C++ exceptions *are* supported)
// CHECK: SUMMARY: AddressSanitizer: stack-buffer-overflow {{.*}} in main
// CHECK: Shadow bytes around the buggy address:
// CHECK: Shadow byte legend (one shadow byte represents 8 application bytes):
// CHECK-NEXT: Addressable: 00
// CHECK-NEXT: Partially addressable: 01 02 03 04 05 06 07
// CHECK-NEXT: Heap left redzone: fa
// CHECK-NEXT: Freed heap region: fd
// CHECK-NEXT: Stack left redzone: f1
// CHECK-NEXT: Stack mid redzone: f2
// CHECK-NEXT: Stack right redzone: f3
// CHECK-NEXT: Stack after return: f5
// CHECK-NEXT: Stack use after scope: f8
// CHECK-NEXT: Global redzone: f9
// CHECK-NEXT: Global init order: f6
// CHECK-NEXT: Poisoned by user: f7
// CHECK-NEXT: Container overflow: fc
// CHECK-NEXT: Array cookie: ac
// CHECK-NEXT: Intra object redzone: bb
// CHECK-NEXT: ASan internal: fe
// CHECK-NEXT: Left alloca redzone: ca
// CHECK-NEXT: Right alloca redzone: cb
printf("Should have failed with ASAN error.\n");
}
50 changes: 50 additions & 0 deletions compiler-rt/test/asan/TestCases/wcsncat.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
// RUN: %clangxx_asan -O0 %s -o %t && not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-%os --check-prefix=CHECK
// RUN: %clangxx_asan -O1 %s -o %t && not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-%os --check-prefix=CHECK
// RUN: %clangxx_asan -O2 %s -o %t && not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-%os --check-prefix=CHECK
// RUN: %clangxx_asan -O3 %s -o %t && not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-%os --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.
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]+}}
// CHECK: #1 [[ADDR:0x[0-9a-f]+]] in main {{.*}}\TestCases\wcsncat.cpp:23
// CHECK: This frame has 2 object(s):
// CHECK: HINT: this may be a false positive if your program uses some custom stack unwind mechanism, swapcontext or vfork
// CHECK: (longjmp, SEH and C++ exceptions *are* supported)
// CHECK: SUMMARY: AddressSanitizer: stack-buffer-overflow {{.*}} in main
// CHECK: Shadow bytes around the buggy address:
// CHECK: Shadow byte legend (one shadow byte represents 8 application bytes):
// CHECK-NEXT: Addressable: 00
// CHECK-NEXT: Partially addressable: 01 02 03 04 05 06 07
// CHECK-NEXT: Heap left redzone: fa
// CHECK-NEXT: Freed heap region: fd
// CHECK-NEXT: Stack left redzone: f1
// CHECK-NEXT: Stack mid redzone: f2
// CHECK-NEXT: Stack right redzone: f3
// CHECK-NEXT: Stack after return: f5
// CHECK-NEXT: Stack use after scope: f8
// CHECK-NEXT: Global redzone: f9
// CHECK-NEXT: Global init order: f6
// CHECK-NEXT: Poisoned by user: f7
// CHECK-NEXT: Container overflow: fc
// CHECK-NEXT: Array cookie: ac
// CHECK-NEXT: Intra object redzone: bb
// CHECK-NEXT: ASan internal: fe
// CHECK-NEXT: Left alloca redzone: ca
// CHECK-NEXT: Right alloca redzone: cb
}
49 changes: 49 additions & 0 deletions compiler-rt/test/asan/TestCases/wcsncpy.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
// RUN: %clangxx_asan -O0 %s -o %t && not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-%os --check-prefix=CHECK
// RUN: %clangxx_asan -O1 %s -o %t && not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-%os --check-prefix=CHECK
// RUN: %clangxx_asan -O2 %s -o %t && not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-%os --check-prefix=CHECK
// RUN: %clangxx_asan -O3 %s -o %t && not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-%os --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.

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]+}}
// CHECK: #1 [[ADDR:0x[0-9a-f]+]] in main {{.*}}\TestCases\wcsncpy.cpp:21
// CHECK: This frame has 2 object(s):
// CHECK: HINT: this may be a false positive if your program uses some custom stack unwind mechanism, swapcontext or vfork
// CHECK: (longjmp, SEH and C++ exceptions *are* supported)
// CHECK: SUMMARY: AddressSanitizer: stack-buffer-overflow {{.*}} in main
// CHECK: Shadow bytes around the buggy address:
// CHECK: Shadow byte legend (one shadow byte represents 8 application bytes):
// CHECK-NEXT: Addressable: 00
// CHECK-NEXT: Partially addressable: 01 02 03 04 05 06 07
// CHECK-NEXT: Heap left redzone: fa
// CHECK-NEXT: Freed heap region: fd
// CHECK-NEXT: Stack left redzone: f1
// CHECK-NEXT: Stack mid redzone: f2
// CHECK-NEXT: Stack right redzone: f3
// CHECK-NEXT: Stack after return: f5
// CHECK-NEXT: Stack use after scope: f8
// CHECK-NEXT: Global redzone: f9
// CHECK-NEXT: Global init order: f6
// CHECK-NEXT: Poisoned by user: f7
// CHECK-NEXT: Container overflow: fc
// CHECK-NEXT: Array cookie: ac
// CHECK-NEXT: Intra object redzone: bb
// CHECK-NEXT: ASan internal: fe
// CHECK-NEXT: Left alloca redzone: ca
// CHECK-NEXT: Right alloca redzone: cb
printf("Should have failed with ASAN error.\n");
}