forked from OSchip/llvm-project
Reland "[compiler-rt] Intercept the bcmp() function."
Fix test issues on darwin: The REQUIRES for the test should be the same as the guard for whether we intercept bcmp. llvm-svn: 355204
This commit is contained in:
parent
6b79f3b1e2
commit
dd885eaf5f
|
@ -9,7 +9,11 @@
|
|||
// This file is a part of AddressSanitizer, an address sanity checker.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
#include <string.h>
|
||||
#include "asan_test_utils.h"
|
||||
#if defined(_GNU_SOURCE)
|
||||
#include <strings.h> // for bcmp
|
||||
#endif
|
||||
#include <vector>
|
||||
|
||||
template<typename T>
|
||||
|
@ -205,37 +209,43 @@ TEST(AddressSanitizer, MemMoveOOBTest) {
|
|||
MemTransferOOBTestTemplate<int, MemMoveWrapper>(1024);
|
||||
}
|
||||
|
||||
|
||||
TEST(AddressSanitizer, MemCmpOOBTest) {
|
||||
template <int (*cmpfn)(const void *, const void *, size_t)>
|
||||
void CmpOOBTestCommon() {
|
||||
size_t size = Ident(100);
|
||||
char *s1 = MallocAndMemsetString(size);
|
||||
char *s2 = MallocAndMemsetString(size);
|
||||
// Normal memcmp calls.
|
||||
Ident(memcmp(s1, s2, size));
|
||||
Ident(memcmp(s1 + size - 1, s2 + size - 1, 1));
|
||||
Ident(memcmp(s1 - 1, s2 - 1, 0));
|
||||
// Normal cmpfn calls.
|
||||
Ident(cmpfn(s1, s2, size));
|
||||
Ident(cmpfn(s1 + size - 1, s2 + size - 1, 1));
|
||||
Ident(cmpfn(s1 - 1, s2 - 1, 0));
|
||||
// One of arguments points to not allocated memory.
|
||||
EXPECT_DEATH(Ident(memcmp)(s1 - 1, s2, 1), LeftOOBReadMessage(1));
|
||||
EXPECT_DEATH(Ident(memcmp)(s1, s2 - 1, 1), LeftOOBReadMessage(1));
|
||||
EXPECT_DEATH(Ident(memcmp)(s1 + size, s2, 1), RightOOBReadMessage(0));
|
||||
EXPECT_DEATH(Ident(memcmp)(s1, s2 + size, 1), RightOOBReadMessage(0));
|
||||
EXPECT_DEATH(Ident(cmpfn)(s1 - 1, s2, 1), LeftOOBReadMessage(1));
|
||||
EXPECT_DEATH(Ident(cmpfn)(s1, s2 - 1, 1), LeftOOBReadMessage(1));
|
||||
EXPECT_DEATH(Ident(cmpfn)(s1 + size, s2, 1), RightOOBReadMessage(0));
|
||||
EXPECT_DEATH(Ident(cmpfn)(s1, s2 + size, 1), RightOOBReadMessage(0));
|
||||
// Hit unallocated memory and die.
|
||||
EXPECT_DEATH(Ident(memcmp)(s1 + 1, s2 + 1, size), RightOOBReadMessage(0));
|
||||
EXPECT_DEATH(Ident(memcmp)(s1 + size - 1, s2, 2), RightOOBReadMessage(0));
|
||||
EXPECT_DEATH(Ident(cmpfn)(s1 + 1, s2 + 1, size), RightOOBReadMessage(0));
|
||||
EXPECT_DEATH(Ident(cmpfn)(s1 + size - 1, s2, 2), RightOOBReadMessage(0));
|
||||
// Zero bytes are not terminators and don't prevent from OOB.
|
||||
s1[size - 1] = '\0';
|
||||
s2[size - 1] = '\0';
|
||||
EXPECT_DEATH(Ident(memcmp)(s1, s2, size + 1), RightOOBReadMessage(0));
|
||||
EXPECT_DEATH(Ident(cmpfn)(s1, s2, size + 1), RightOOBReadMessage(0));
|
||||
|
||||
// Even if the buffers differ in the first byte, we still assume that
|
||||
// memcmp may access the whole buffer and thus reporting the overflow here:
|
||||
// cmpfn may access the whole buffer and thus reporting the overflow here:
|
||||
s1[0] = 1;
|
||||
s2[0] = 123;
|
||||
EXPECT_DEATH(Ident(memcmp)(s1, s2, size + 1), RightOOBReadMessage(0));
|
||||
EXPECT_DEATH(Ident(cmpfn)(s1, s2, size + 1), RightOOBReadMessage(0));
|
||||
|
||||
free(s1);
|
||||
free(s2);
|
||||
}
|
||||
|
||||
TEST(AddressSanitizer, MemCmpOOBTest) { CmpOOBTestCommon<memcmp>(); }
|
||||
|
||||
|
||||
TEST(AddressSanitizer, BCmpOOBTest) {
|
||||
#if (defined(__linux__) && !defined(__ANDROID__) && defined(_GNU_SOURCE)) || \
|
||||
defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__)
|
||||
CmpOOBTestCommon<bcmp>();
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -819,16 +819,14 @@ INTERCEPTOR(void *, memcpy, void *dst, const void *src, uptr size) {
|
|||
#endif
|
||||
|
||||
#if SANITIZER_INTERCEPT_MEMCMP
|
||||
|
||||
DECLARE_WEAK_INTERCEPTOR_HOOK(__sanitizer_weak_hook_memcmp, uptr called_pc,
|
||||
const void *s1, const void *s2, uptr n,
|
||||
int result)
|
||||
|
||||
INTERCEPTOR(int, memcmp, const void *a1, const void *a2, uptr size) {
|
||||
if (COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED)
|
||||
return internal_memcmp(a1, a2, size);
|
||||
void *ctx;
|
||||
COMMON_INTERCEPTOR_ENTER(ctx, memcmp, a1, a2, size);
|
||||
// Common code for `memcmp` and `bcmp`.
|
||||
int MemcmpInterceptorCommon(void *ctx,
|
||||
int (*real_fn)(const void *, const void *, uptr),
|
||||
const void *a1, const void *a2, uptr size) {
|
||||
if (common_flags()->intercept_memcmp) {
|
||||
if (common_flags()->strict_memcmp) {
|
||||
// Check the entire regions even if the first bytes of the buffers are
|
||||
|
@ -854,17 +852,39 @@ INTERCEPTOR(int, memcmp, const void *a1, const void *a2, uptr size) {
|
|||
return r;
|
||||
}
|
||||
}
|
||||
int result = REAL(memcmp(a1, a2, size));
|
||||
int result = real_fn(a1, a2, size);
|
||||
CALL_WEAK_INTERCEPTOR_HOOK(__sanitizer_weak_hook_memcmp, GET_CALLER_PC(), a1,
|
||||
a2, size, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
INTERCEPTOR(int, memcmp, const void *a1, const void *a2, uptr size) {
|
||||
if (COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED)
|
||||
return internal_memcmp(a1, a2, size);
|
||||
void *ctx;
|
||||
COMMON_INTERCEPTOR_ENTER(ctx, memcmp, a1, a2, size);
|
||||
return MemcmpInterceptorCommon(ctx, REAL(memcmp), a1, a2, size);
|
||||
}
|
||||
|
||||
#define INIT_MEMCMP COMMON_INTERCEPT_FUNCTION(memcmp)
|
||||
#else
|
||||
#define INIT_MEMCMP
|
||||
#endif
|
||||
|
||||
#if SANITIZER_INTERCEPT_BCMP
|
||||
INTERCEPTOR(int, bcmp, const void *a1, const void *a2, uptr size) {
|
||||
if (COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED)
|
||||
return internal_memcmp(a1, a2, size);
|
||||
void *ctx;
|
||||
COMMON_INTERCEPTOR_ENTER(ctx, bcmp, a1, a2, size);
|
||||
return MemcmpInterceptorCommon(ctx, REAL(bcmp), a1, a2, size);
|
||||
}
|
||||
|
||||
#define INIT_BCMP COMMON_INTERCEPT_FUNCTION(bcmp)
|
||||
#else
|
||||
#define INIT_BCMP
|
||||
#endif
|
||||
|
||||
#if SANITIZER_INTERCEPT_MEMCHR
|
||||
INTERCEPTOR(void*, memchr, const void *s, int c, SIZE_T n) {
|
||||
if (COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED)
|
||||
|
@ -9492,6 +9512,7 @@ static void InitializeCommonInterceptors() {
|
|||
INIT_MEMCPY;
|
||||
INIT_MEMCHR;
|
||||
INIT_MEMCMP;
|
||||
INIT_BCMP;
|
||||
INIT_MEMRCHR;
|
||||
INIT_MEMMEM;
|
||||
INIT_READ;
|
||||
|
|
|
@ -142,6 +142,9 @@
|
|||
#define SANITIZER_INTERCEPT_MEMMOVE 1
|
||||
#define SANITIZER_INTERCEPT_MEMCPY 1
|
||||
#define SANITIZER_INTERCEPT_MEMCMP SI_NOT_FUCHSIA
|
||||
#define SANITIZER_INTERCEPT_BCMP \
|
||||
SANITIZER_INTERCEPT_MEMCMP && \
|
||||
((SI_POSIX && _GNU_SOURCE) || SI_NETBSD || SI_OPENBSD || SI_FREEBSD)
|
||||
#define SANITIZER_INTERCEPT_STRNDUP SI_POSIX
|
||||
#define SANITIZER_INTERCEPT___STRNDUP SI_LINUX_NOT_FREEBSD
|
||||
#if defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) && \
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
// RUN: %clangxx_asan -O0 %s -o %t && not %run %t 2>&1 | FileCheck %s
|
||||
// RUN: %clangxx_asan -O1 %s -o %t && not %run %t 2>&1 | FileCheck %s
|
||||
// RUN: %clangxx_asan -O2 %s -o %t && not %run %t 2>&1 | FileCheck %s
|
||||
// RUN: %clangxx_asan -O3 %s -o %t && not %run %t 2>&1 | FileCheck %s
|
||||
|
||||
// REQUIRES: compiler-rt-optimized, (linux && !android) || openbsd || freebsd || netbsd
|
||||
// XFAIL: darwin
|
||||
|
||||
#include <string.h>
|
||||
int main(int argc, char **argv) {
|
||||
char a1[] = {static_cast<char>(argc), 2, 3, 4};
|
||||
char a2[] = {1, static_cast<char>(2 * argc), 3, 4};
|
||||
int res = bcmp(a1, a2, 4 + argc); // BOOM
|
||||
// CHECK: AddressSanitizer: stack-buffer-overflow
|
||||
// CHECK: {{#1.*bcmp}}
|
||||
// CHECK: {{#2.*main}}
|
||||
return res;
|
||||
}
|
|
@ -11,7 +11,7 @@ int main(int argc, char **argv) {
|
|||
char a2[] = {1, static_cast<char>(2*argc), 3, 4};
|
||||
int res = memcmp(a1, a2, 4 + argc); // BOOM
|
||||
// CHECK: AddressSanitizer: stack-buffer-overflow
|
||||
// CHECK: {{#0.*memcmp}}
|
||||
// CHECK: {{#1.*main}}
|
||||
// CHECK: {{#1.*memcmp}}
|
||||
// CHECK: {{#2.*main}}
|
||||
return res;
|
||||
}
|
||||
|
|
|
@ -13,6 +13,6 @@ int main(int argc, char **argv) {
|
|||
if (!res)
|
||||
printf("equals");
|
||||
return 0;
|
||||
// CHECK: Uninitialized bytes in __interceptor_memcmp at offset 3
|
||||
// CHECK: Uninitialized bytes in MemcmpInterceptorCommon at offset 3
|
||||
// CHECK: MemorySanitizer: use-of-uninitialized-value
|
||||
}
|
||||
|
|
|
@ -37,7 +37,7 @@ int main(int argc, char *argv[]) {
|
|||
case '2': {
|
||||
int cmp = memcmp(uninit, uninit, sizeof(uninit)); // BOOM
|
||||
break;
|
||||
// CASE-2: Uninitialized bytes in __interceptor_memcmp
|
||||
// CASE-2: Uninitialized bytes in MemcmpInterceptorCommon
|
||||
}
|
||||
case '3': {
|
||||
size_t len = strlen(uninit); // BOOM
|
||||
|
|
|
@ -6,8 +6,11 @@
|
|||
// XFAIL: lsan
|
||||
// XFAIL: ubsan
|
||||
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#if defined(_GNU_SOURCE)
|
||||
#include <strings.h> // for bcmp
|
||||
#endif
|
||||
|
||||
bool seen_memcmp, seen_strncmp, seen_strncasecmp, seen_strcmp, seen_strcasecmp,
|
||||
seen_strstr, seen_strcasestr, seen_memmem;
|
||||
|
@ -59,6 +62,12 @@ int main() {
|
|||
int_sink = memcmp(s1, s2, sizeof(s2));
|
||||
assert(seen_memcmp);
|
||||
|
||||
#if (defined(__linux__) && !defined(__ANDROID__) && defined(_GNU_SOURCE)) || defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__)
|
||||
seen_memcmp = false;
|
||||
int_sink = bcmp(s1, s2, sizeof(s2));
|
||||
assert(seen_memcmp);
|
||||
#endif
|
||||
|
||||
int_sink = strncmp(s1, s2, sizeof(s2));
|
||||
assert(seen_strncmp);
|
||||
|
||||
|
|
Loading…
Reference in New Issue