diff options
Diffstat (limited to 'compiler-rt')
| -rw-r--r-- | compiler-rt/lib/tysan/tysan.cpp | 121 | ||||
| -rw-r--r-- | compiler-rt/lib/tysan/tysan_platform.h | 16 | ||||
| -rw-r--r-- | compiler-rt/test/asan/TestCases/Darwin/suppressions-sandbox.cpp | 3 | ||||
| -rw-r--r-- | compiler-rt/test/asan/TestCases/Posix/fread_fwrite.cpp | 3 | ||||
| -rw-r--r-- | compiler-rt/test/tysan/basic.c | 8 | ||||
| -rw-r--r-- | compiler-rt/test/tysan/simple_verify_outlines.c | 22 | ||||
| -rw-r--r-- | compiler-rt/test/tysan/struct-offset-outline.c | 32 |
7 files changed, 194 insertions, 11 deletions
diff --git a/compiler-rt/lib/tysan/tysan.cpp b/compiler-rt/lib/tysan/tysan.cpp index 4fa8166..1c67ade 100644 --- a/compiler-rt/lib/tysan/tysan.cpp +++ b/compiler-rt/lib/tysan/tysan.cpp @@ -22,6 +22,7 @@ #include "tysan/tysan.h" +#include <stdint.h> #include <string.h> using namespace __sanitizer; @@ -254,10 +255,68 @@ static void reportError(void *Addr, int Size, tysan_type_descriptor *TD, } } +ALWAYS_INLINE +static void SetShadowType(tysan_type_descriptor *td, + tysan_type_descriptor **shadowData, + uint64_t AccessSize) { + *shadowData = td; + uint64_t shadowDataInt = (uint64_t)shadowData; + + for (uint64_t i = 1; i < AccessSize; ++i) { + int64_t dataOffset = i << PtrShift(); + int64_t *badShadowData = (int64_t *)(shadowDataInt + dataOffset); + int64_t badTD = int64_t(i) * -1; + *badShadowData = badTD; + } +} + +ALWAYS_INLINE +static bool GetNotAllBadTD(uint64_t ShadowDataInt, uint64_t AccessSize) { + bool notAllBadTD = false; + for (uint64_t i = 1; i < AccessSize; ++i) { + int64_t **unkShadowData = (int64_t **)(ShadowDataInt + (i << PtrShift())); + int64_t *ILdTD = *unkShadowData; + notAllBadTD = notAllBadTD || (ILdTD != nullptr); + } + return notAllBadTD; +} + +ALWAYS_INLINE +static bool GetNotAllUnkTD(uint64_t ShadowDataInt, uint64_t AccessSize) { + bool notAllBadTD = false; + for (uint64_t i = 1; i < AccessSize; ++i) { + int64_t *badShadowData = (int64_t *)(ShadowDataInt + (i << PtrShift())); + int64_t ILdTD = *badShadowData; + notAllBadTD = notAllBadTD || (ILdTD >= 0); + } + return notAllBadTD; +} + extern "C" SANITIZER_INTERFACE_ATTRIBUTE void -__tysan_check(void *addr, int size, tysan_type_descriptor *td, int flags) { - GET_CALLER_PC_BP_SP; +__tysan_instrument_mem_inst(char *dest, char *src, uint64_t size, + bool needsMemMove) { + tysan_type_descriptor **destShadowDataPtr = shadow_for(dest); + + if (!src) { + internal_memset((char *)destShadowDataPtr, 0, size << PtrShift()); + return; + } + + uint64_t srcInt = (uint64_t)src; + uint64_t srcShadowInt = ((srcInt & AppMask()) << PtrShift()) + ShadowAddr(); + uint64_t *srcShadow = (uint64_t *)srcShadowInt; + if (needsMemMove) { + internal_memmove((char *)destShadowDataPtr, srcShadow, size << PtrShift()); + } else { + internal_memcpy((char *)destShadowDataPtr, srcShadow, size << PtrShift()); + } +} + +ALWAYS_INLINE +static void __tysan_check_internal(void *addr, int size, + tysan_type_descriptor *td, int flags, + uptr pc, uptr bp, uptr sp) { bool IsRead = flags & 1; bool IsWrite = flags & 2; const char *AccessStr; @@ -300,6 +359,64 @@ __tysan_check(void *addr, int size, tysan_type_descriptor *td, int flags) { } } +extern "C" SANITIZER_INTERFACE_ATTRIBUTE void +__tysan_check(void *addr, int size, tysan_type_descriptor *td, int flags) { + GET_CALLER_PC_BP_SP; + __tysan_check_internal(addr, size, td, flags, pc, bp, sp); +} + +extern "C" SANITIZER_INTERFACE_ATTRIBUTE void +__tysan_instrument_with_shadow_update(void *ptr, tysan_type_descriptor *td, + bool sanitizeFunction, + uint64_t accessSize, int flags) { + tysan_type_descriptor **shadowData = shadow_for(ptr); + tysan_type_descriptor *loadedTD = *shadowData; + bool shadowIsNull = loadedTD == nullptr; + + // TODO, sanitizeFunction is known at compile time, so maybe this is split + // into two different functions + if (sanitizeFunction) { + + if (td != loadedTD) { + + // We now know that the types did not match (we're on the slow path). If + // the type is unknown, then set it. + if (shadowIsNull) { + // We're about to set the type. Make sure that all bytes in the value + // are also of unknown type. + bool isAllUnknownTD = GetNotAllUnkTD((uint64_t)shadowData, accessSize); + if (isAllUnknownTD) { + GET_CALLER_PC_BP_SP; + __tysan_check_internal(ptr, accessSize, td, flags, pc, bp, sp); + } + SetShadowType(td, shadowData, accessSize); + } else { + GET_CALLER_PC_BP_SP; + __tysan_check_internal(ptr, accessSize, td, flags, pc, bp, sp); + } + } else { + // We appear to have the right type. Make sure that all other bytes in + // the type are still marked as interior bytes. If not, call the runtime. + bool isNotAllBadTD = GetNotAllBadTD((uint64_t)shadowData, accessSize); + if (isNotAllBadTD) { + GET_CALLER_PC_BP_SP; + __tysan_check_internal(ptr, accessSize, td, flags, pc, bp, sp); + } + } + } else if (shadowIsNull) { + SetShadowType(td, shadowData, accessSize); + } +} + +extern "C" SANITIZER_INTERFACE_ATTRIBUTE void +__tysan_set_shadow_type(void *ptr, tysan_type_descriptor *td, + uint64_t accessSize) { + // In the mode where writes always set the type, for a write (which does + // not also read), we just set the type. + tysan_type_descriptor **shadow = shadow_for(ptr); + SetShadowType(td, shadow, accessSize); +} + Flags __tysan::flags_data; SANITIZER_INTERFACE_ATTRIBUTE uptr __tysan_shadow_memory_address; diff --git a/compiler-rt/lib/tysan/tysan_platform.h b/compiler-rt/lib/tysan/tysan_platform.h index f013928..19f77f0 100644 --- a/compiler-rt/lib/tysan/tysan_platform.h +++ b/compiler-rt/lib/tysan/tysan_platform.h @@ -21,24 +21,28 @@ struct Mapping { static const uptr kShadowAddr = 0x010000000000ull; static const uptr kAppAddr = 0x550000000000ull; static const uptr kAppMemMsk = ~0x780000000000ull; + static const uptr kPtrShift = 3; }; #elif defined(__aarch64__) struct Mapping39 { static const uptr kShadowAddr = 0x0800000000ull; static const uptr kAppAddr = 0x5500000000ull; static const uptr kAppMemMsk = ~0x7800000000ull; + static const uptr kPtrShift = 3; }; struct Mapping42 { static const uptr kShadowAddr = 0x10000000000ull; static const uptr kAppAddr = 0x2aa00000000ull; static const uptr kAppMemMsk = ~0x3c000000000ull; + static const uptr kPtrShift = 3; }; struct Mapping48 { static const uptr kShadowAddr = 0x0002000000000ull; static const uptr kAppAddr = 0x0aaaa00000000ull; static const uptr kAppMemMsk = ~0x0fff800000000ull; + static const uptr kPtrShift = 3; }; #define TYSAN_RUNTIME_VMA 1 #else @@ -49,7 +53,12 @@ struct Mapping48 { extern int vmaSize; #endif -enum MappingType { MAPPING_SHADOW_ADDR, MAPPING_APP_ADDR, MAPPING_APP_MASK }; +enum MappingType { + MAPPING_SHADOW_ADDR, + MAPPING_APP_ADDR, + MAPPING_APP_MASK, + MAPPING_PTR_SHIFT +}; template <typename Mapping, int Type> uptr MappingImpl(void) { switch (Type) { @@ -59,6 +68,8 @@ template <typename Mapping, int Type> uptr MappingImpl(void) { return Mapping::kAppAddr; case MAPPING_APP_MASK: return Mapping::kAppMemMsk; + case MAPPING_PTR_SHIFT: + return Mapping::kPtrShift; } } @@ -88,6 +99,9 @@ uptr AppAddr() { return MappingArchImpl<MAPPING_APP_ADDR>(); } ALWAYS_INLINE uptr AppMask() { return MappingArchImpl<MAPPING_APP_MASK>(); } +ALWAYS_INLINE +uptr PtrShift() { return MappingArchImpl<MAPPING_PTR_SHIFT>(); } + } // namespace __tysan #endif diff --git a/compiler-rt/test/asan/TestCases/Darwin/suppressions-sandbox.cpp b/compiler-rt/test/asan/TestCases/Darwin/suppressions-sandbox.cpp index f12e2b2..651d0c5 100644 --- a/compiler-rt/test/asan/TestCases/Darwin/suppressions-sandbox.cpp +++ b/compiler-rt/test/asan/TestCases/Darwin/suppressions-sandbox.cpp @@ -15,9 +15,6 @@ // sandbox-exec isn't available on iOS // UNSUPPORTED: ios -// Symbolizer fails to find test functions on current macOS bot version -// XFAIL: system-darwin && target=arm{{.*}} - #include <CoreFoundation/CoreFoundation.h> #if defined(SHARED_LIB) diff --git a/compiler-rt/test/asan/TestCases/Posix/fread_fwrite.cpp b/compiler-rt/test/asan/TestCases/Posix/fread_fwrite.cpp index c7b9280..c062926 100644 --- a/compiler-rt/test/asan/TestCases/Posix/fread_fwrite.cpp +++ b/compiler-rt/test/asan/TestCases/Posix/fread_fwrite.cpp @@ -2,9 +2,6 @@ // RUN: not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-FWRITE // RUN: not %run %t 1 2>&1 | FileCheck %s --check-prefix=CHECK-FREAD -// Symbolizer fails to find test functions on current macOS bot version -// XFAIL: system-darwin && target=arm{{.*}} - #include <stdio.h> #include <stdlib.h> diff --git a/compiler-rt/test/tysan/basic.c b/compiler-rt/test/tysan/basic.c index 8e66e1a..28b94c4 100644 --- a/compiler-rt/test/tysan/basic.c +++ b/compiler-rt/test/tysan/basic.c @@ -1,6 +1,10 @@ -// RUN: %clang_tysan -O0 %s -o %t && %run %t 10 >%t.out.0 2>&1 +// RUN: %clang_tysan -O0 -mllvm -tysan-outline-instrumentation=false %s -o %t && %run %t 10 >%t.out.0 2>&1 // RUN: FileCheck %s < %t.out.0 -// RUN: %clang_tysan -O2 %s -o %t && %run %t 10 >%t.out 2>&1 +// RUN: %clang_tysan -O2 -mllvm -tysan-outline-instrumentation=false %s -o %t && %run %t 10 >%t.out 2>&1 +// RUN: FileCheck %s < %t.out +// RUN: %clang_tysan -O0 -mllvm -tysan-outline-instrumentation=true %s -o %t && %run %t 10 >%t.out.0 2>&1 +// RUN: FileCheck %s < %t.out.0 +// RUN: %clang_tysan -O2 -mllvm -tysan-outline-instrumentation=true %s -o %t && %run %t 10 >%t.out 2>&1 // RUN: FileCheck %s < %t.out #include <stdio.h> diff --git a/compiler-rt/test/tysan/simple_verify_outlines.c b/compiler-rt/test/tysan/simple_verify_outlines.c new file mode 100644 index 0000000..0d0730e --- /dev/null +++ b/compiler-rt/test/tysan/simple_verify_outlines.c @@ -0,0 +1,22 @@ +// RUN: %clang_tysan -mllvm -tysan-outline-instrumentation=true -mllvm -tysan-verify-outlined-instrumentation=true %s -o %t && %run %t >%t.out.0 2>&1 +// RUN: FileCheck %s < %t.out.0 + +#include <stdio.h> + +void printInt(int *i) { printf("%d\n", *i); } + +int main() { + + float value = 5.0f; + printInt((int *)&value); + + return 0; +} + +// CHECK: ERROR: TypeSanitizer: type-aliasing-violation +// CHECK-NEXT: READ of size 4 at {{.*}} with type int accesses an existing object of type float +// CHECK-NEXT: {{#0 0x.* in printInt}} +// CHECK-EMPTY: +// CHECK-NEXT: ERROR: TypeSanitizer: type-aliasing-violation +// CHECK-NEXT: READ of size 4 at {{.*}} with type int accesses an existing object of type float +// CHECK-NEXT: {{#0 0x.* in printInt}} diff --git a/compiler-rt/test/tysan/struct-offset-outline.c b/compiler-rt/test/tysan/struct-offset-outline.c new file mode 100644 index 0000000..c84eb2762 --- /dev/null +++ b/compiler-rt/test/tysan/struct-offset-outline.c @@ -0,0 +1,32 @@ +// RUN: %clang_tysan -mllvm -tysan-outline-instrumentation=true -O0 %s -o %t && %run %t >%t.out 2>&1 +// RUN: FileCheck %s < %t.out +// RUN: %clang_tysan -mllvm -tysan-outline-instrumentation=true -mllvm -tysan-verify-outlined-instrumentation=true -O0 %s -o %t && %run %t >%t.out 2>&1 +// RUN: FileCheck %s --check-prefixes='CHECK,CHECK-VERIFY' < %t.out + +#include <stdio.h> +#include <stdlib.h> + +struct X { + int i; + int j; +}; + +int foo(struct X *p, struct X *q) { + q->j = 1; + p->i = 0; + // CHECK: ERROR: TypeSanitizer: type-aliasing-violation + // CHECK-NEXT: WRITE of size 4 at {{.*}} with type int (in X at offset 0) accesses an existing object of type int (in X at offset 4) + // CHECK-NEXT: {{#0 0x.* in foo .*struct-offset-outline.c:}}[[@LINE-3]] + // CHECK-VERIFY-EMPTY: + // CHECK-VERIFY-NEXT: ERROR: TypeSanitizer: type-aliasing-violation + // CHECK-VERIFY-NEXT: WRITE of size 4 at {{.*}} with type int (in X at offset 0) accesses an existing object of type int (in X at offset 4) + // CHECK-VERIFY-NEXT: {{#0 0x.* in foo .*struct-offset-outline.c:}}[[@LINE-7]] + return q->j; +} + +int main() { + unsigned char *p = malloc(3 * sizeof(int)); + printf("%i\n", foo((struct X *)(p + sizeof(int)), (struct X *)p)); +} + +// CHECK-NOT: ERROR: TypeSanitizer: type-aliasing-violation |
