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;
|
||||
// Use stack depot instead of storing stacks in the redzones.
|
||||
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();
|
||||
|
|
|
@ -260,10 +260,26 @@ INTERCEPTOR(int, memcmp, const void *a1, const void *a2, uptr size) {
|
|||
if (!asan_inited) return internal_memcmp(a1, a2, size);
|
||||
ENSURE_ASAN_INITED();
|
||||
if (flags()->replace_intrin) {
|
||||
// We check the entire regions even if the first bytes of the buffers
|
||||
// are different.
|
||||
ASAN_READ_RANGE(a1, size);
|
||||
ASAN_READ_RANGE(a2, size);
|
||||
if (flags()->strict_memcmp) {
|
||||
// Check the entire regions even if the first bytes of the buffers are
|
||||
// different.
|
||||
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));
|
||||
}
|
||||
|
|
|
@ -127,6 +127,7 @@ static void ParseFlagsFromString(Flags *f, const char *str) {
|
|||
ParseFlag(str, &f->poison_heap, "poison_heap");
|
||||
ParseFlag(str, &f->alloc_dealloc_mismatch, "alloc_dealloc_mismatch");
|
||||
ParseFlag(str, &f->use_stack_depot, "use_stack_depot");
|
||||
ParseFlag(str, &f->strict_memcmp, "strict_memcmp");
|
||||
}
|
||||
|
||||
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.
|
||||
f->alloc_dealloc_mismatch = (ASAN_MAC == 0);;
|
||||
f->use_stack_depot = true; // Only affects allocator2.
|
||||
f->strict_memcmp = true;
|
||||
|
||||
// Override from compile definition.
|
||||
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