forked from OSchip/llvm-project
[ASan] Add the memcmp_strict flag (1 by default) that controls the behavior of accessibility checks in memcmp.
1: memcmp(p1, p2, n) always checks n bytes 0: memcmp checks up to n bytes depending on whether the memory contents differ. llvm-svn: 176256
This commit is contained in:
parent
1cb95a17b8
commit
f1c48eb509
|
@ -110,6 +110,9 @@ struct Flags {
|
||||||
bool alloc_dealloc_mismatch;
|
bool alloc_dealloc_mismatch;
|
||||||
// Use stack depot instead of storing stacks in the redzones.
|
// Use stack depot instead of storing stacks in the redzones.
|
||||||
bool use_stack_depot;
|
bool use_stack_depot;
|
||||||
|
// If true, assume that memcmp(p1, p2, n) always reads n bytes before
|
||||||
|
// comparing p1 and p2.
|
||||||
|
bool strict_memcmp;
|
||||||
};
|
};
|
||||||
|
|
||||||
Flags *flags();
|
Flags *flags();
|
||||||
|
|
|
@ -260,10 +260,26 @@ INTERCEPTOR(int, memcmp, const void *a1, const void *a2, uptr size) {
|
||||||
if (!asan_inited) return internal_memcmp(a1, a2, size);
|
if (!asan_inited) return internal_memcmp(a1, a2, size);
|
||||||
ENSURE_ASAN_INITED();
|
ENSURE_ASAN_INITED();
|
||||||
if (flags()->replace_intrin) {
|
if (flags()->replace_intrin) {
|
||||||
// We check the entire regions even if the first bytes of the buffers
|
if (flags()->strict_memcmp) {
|
||||||
// are different.
|
// Check the entire regions even if the first bytes of the buffers are
|
||||||
ASAN_READ_RANGE(a1, size);
|
// different.
|
||||||
ASAN_READ_RANGE(a2, size);
|
ASAN_READ_RANGE(a1, size);
|
||||||
|
ASAN_READ_RANGE(a2, size);
|
||||||
|
// Fallthrough to REAL(memcmp) below.
|
||||||
|
} else {
|
||||||
|
unsigned char c1 = 0, c2 = 0;
|
||||||
|
const unsigned char *s1 = (const unsigned char*)a1;
|
||||||
|
const unsigned char *s2 = (const unsigned char*)a2;
|
||||||
|
uptr i;
|
||||||
|
for (i = 0; i < size; i++) {
|
||||||
|
c1 = s1[i];
|
||||||
|
c2 = s2[i];
|
||||||
|
if (c1 != c2) break;
|
||||||
|
}
|
||||||
|
ASAN_READ_RANGE(s1, Min(i + 1, size));
|
||||||
|
ASAN_READ_RANGE(s2, Min(i + 1, size));
|
||||||
|
return CharCmp(c1, c2);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return REAL(memcmp(a1, a2, size));
|
return REAL(memcmp(a1, a2, size));
|
||||||
}
|
}
|
||||||
|
|
|
@ -127,6 +127,7 @@ static void ParseFlagsFromString(Flags *f, const char *str) {
|
||||||
ParseFlag(str, &f->poison_heap, "poison_heap");
|
ParseFlag(str, &f->poison_heap, "poison_heap");
|
||||||
ParseFlag(str, &f->alloc_dealloc_mismatch, "alloc_dealloc_mismatch");
|
ParseFlag(str, &f->alloc_dealloc_mismatch, "alloc_dealloc_mismatch");
|
||||||
ParseFlag(str, &f->use_stack_depot, "use_stack_depot");
|
ParseFlag(str, &f->use_stack_depot, "use_stack_depot");
|
||||||
|
ParseFlag(str, &f->strict_memcmp, "strict_memcmp");
|
||||||
}
|
}
|
||||||
|
|
||||||
void InitializeFlags(Flags *f, const char *env) {
|
void InitializeFlags(Flags *f, const char *env) {
|
||||||
|
@ -168,6 +169,7 @@ void InitializeFlags(Flags *f, const char *env) {
|
||||||
// TODO(glider): Fix known issues and enable this back.
|
// TODO(glider): Fix known issues and enable this back.
|
||||||
f->alloc_dealloc_mismatch = (ASAN_MAC == 0);;
|
f->alloc_dealloc_mismatch = (ASAN_MAC == 0);;
|
||||||
f->use_stack_depot = true; // Only affects allocator2.
|
f->use_stack_depot = true; // Only affects allocator2.
|
||||||
|
f->strict_memcmp = true;
|
||||||
|
|
||||||
// Override from compile definition.
|
// Override from compile definition.
|
||||||
ParseFlagsFromString(f, MaybeUseAsanDefaultOptionsCompileDefiniton());
|
ParseFlagsFromString(f, MaybeUseAsanDefaultOptionsCompileDefiniton());
|
||||||
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
// RUN: %clangxx_asan -m64 -O0 %s -o %t && ASAN_OPTIONS=strict_memcmp=0 %t 2>&1 | %symbolize | FileCheck %s --check-prefix=CHECK-nonstrict
|
||||||
|
// RUN: %clangxx_asan -m64 -O0 %s -o %t && ASAN_OPTIONS=strict_memcmp=1 %t 2>&1 | %symbolize | FileCheck %s --check-prefix=CHECK-strict
|
||||||
|
// Default to strict_memcmp=1.
|
||||||
|
// RUN: %clangxx_asan -m64 -O0 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s --check-prefix=CHECK-strict
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
int main() {
|
||||||
|
char kFoo[] = "foo";
|
||||||
|
char kFubar[] = "fubar";
|
||||||
|
int res = memcmp(kFoo, kFubar, strlen(kFubar));
|
||||||
|
printf("res: %d\n", res);
|
||||||
|
// CHECK-nonstrict: {{res: -1}}
|
||||||
|
// CHECK-strict: AddressSanitizer: stack-buffer-overflow
|
||||||
|
return 0;
|
||||||
|
}
|
Loading…
Reference in New Issue