diff options
author | Alex Shlyapnikov <alekseys@google.com> | 2017-12-22 17:02:17 +0000 |
---|---|---|
committer | Alex Shlyapnikov <alekseys@google.com> | 2017-12-22 17:02:17 +0000 |
commit | 5ca33a137a83299335b8164ea3a9157b1e12ae70 (patch) | |
tree | da142797c28055b68af1257c9eae8571b7f86a3b /compiler-rt | |
parent | 4ce902657a9ed376fe76019a9431751cf83e6f28 (diff) | |
download | llvm-5ca33a137a83299335b8164ea3a9157b1e12ae70.zip llvm-5ca33a137a83299335b8164ea3a9157b1e12ae70.tar.gz llvm-5ca33a137a83299335b8164ea3a9157b1e12ae70.tar.bz2 |
[MSan,TSan] Add aligned new/delete interceptors.
Summary:
Providing aligned new/delete implementations to match ASan.
Unlike ASan, MSan and TSan do not perform any additional checks
on overaligned memory, hence no sanitizer specific tests.
Reviewers: eugenis
Subscribers: kubamracek, #sanitizers, llvm-commits
Differential Revision: https://reviews.llvm.org/D41532
llvm-svn: 321365
Diffstat (limited to 'compiler-rt')
-rw-r--r-- | compiler-rt/lib/msan/msan_new_delete.cc | 44 | ||||
-rw-r--r-- | compiler-rt/lib/tsan/rtl/tsan_new_delete.cc | 97 | ||||
-rw-r--r-- | compiler-rt/test/sanitizer_common/TestCases/Linux/new_delete_test.cc | 80 |
3 files changed, 220 insertions, 1 deletions
diff --git a/compiler-rt/lib/msan/msan_new_delete.cc b/compiler-rt/lib/msan/msan_new_delete.cc index 7219267..5cc76e4 100644 --- a/compiler-rt/lib/msan/msan_new_delete.cc +++ b/compiler-rt/lib/msan/msan_new_delete.cc @@ -22,9 +22,10 @@ using namespace __msan; // NOLINT -// Fake std::nothrow_t to avoid including <new>. +// Fake std::nothrow_t and std::align_val_t to avoid including <new>. namespace std { struct nothrow_t {}; + enum class align_val_t: size_t {}; } // namespace std @@ -34,6 +35,11 @@ namespace std { void *res = msan_malloc(size, &stack);\ if (!nothrow && UNLIKELY(!res)) DieOnFailure::OnOOM();\ return res +#define OPERATOR_NEW_BODY_ALIGN(nothrow) \ + GET_MALLOC_STACK_TRACE;\ + void *res = msan_memalign((uptr)align, size, &stack);\ + if (!nothrow && UNLIKELY(!res)) DieOnFailure::OnOOM();\ + return res; INTERCEPTOR_ATTRIBUTE void *operator new(size_t size) { OPERATOR_NEW_BODY(false /*nothrow*/); } @@ -47,6 +53,18 @@ INTERCEPTOR_ATTRIBUTE void *operator new[](size_t size, std::nothrow_t const&) { OPERATOR_NEW_BODY(true /*nothrow*/); } +INTERCEPTOR_ATTRIBUTE +void *operator new(size_t size, std::align_val_t align) +{ OPERATOR_NEW_BODY_ALIGN(false /*nothrow*/); } +INTERCEPTOR_ATTRIBUTE +void *operator new[](size_t size, std::align_val_t align) +{ OPERATOR_NEW_BODY_ALIGN(false /*nothrow*/); } +INTERCEPTOR_ATTRIBUTE +void *operator new(size_t size, std::align_val_t align, std::nothrow_t const&) +{ OPERATOR_NEW_BODY_ALIGN(true /*nothrow*/); } +INTERCEPTOR_ATTRIBUTE +void *operator new[](size_t size, std::align_val_t align, std::nothrow_t const&) +{ OPERATOR_NEW_BODY_ALIGN(true /*nothrow*/); } #define OPERATOR_DELETE_BODY \ GET_MALLOC_STACK_TRACE; \ @@ -62,5 +80,29 @@ INTERCEPTOR_ATTRIBUTE void operator delete[](void *ptr, std::nothrow_t const&) { OPERATOR_DELETE_BODY; } +INTERCEPTOR_ATTRIBUTE +void operator delete(void *ptr, size_t size) NOEXCEPT { OPERATOR_DELETE_BODY; } +INTERCEPTOR_ATTRIBUTE +void operator delete[](void *ptr, size_t size) NOEXCEPT +{ OPERATOR_DELETE_BODY; } +INTERCEPTOR_ATTRIBUTE +void operator delete(void *ptr, std::align_val_t align) NOEXCEPT +{ OPERATOR_DELETE_BODY; } +INTERCEPTOR_ATTRIBUTE +void operator delete[](void *ptr, std::align_val_t align) NOEXCEPT +{ OPERATOR_DELETE_BODY; } +INTERCEPTOR_ATTRIBUTE +void operator delete(void *ptr, std::align_val_t align, std::nothrow_t const&) +{ OPERATOR_DELETE_BODY; } +INTERCEPTOR_ATTRIBUTE +void operator delete[](void *ptr, std::align_val_t align, std::nothrow_t const&) +{ OPERATOR_DELETE_BODY; } +INTERCEPTOR_ATTRIBUTE +void operator delete(void *ptr, size_t size, std::align_val_t align) NOEXCEPT +{ OPERATOR_DELETE_BODY; } +INTERCEPTOR_ATTRIBUTE +void operator delete[](void *ptr, size_t size, std::align_val_t align) NOEXCEPT +{ OPERATOR_DELETE_BODY; } + #endif // MSAN_REPLACE_OPERATORS_NEW_AND_DELETE diff --git a/compiler-rt/lib/tsan/rtl/tsan_new_delete.cc b/compiler-rt/lib/tsan/rtl/tsan_new_delete.cc index 4d03145..a1bb226 100644 --- a/compiler-rt/lib/tsan/rtl/tsan_new_delete.cc +++ b/compiler-rt/lib/tsan/rtl/tsan_new_delete.cc @@ -20,6 +20,7 @@ using namespace __tsan; // NOLINT namespace std { struct nothrow_t {}; +enum class align_val_t: __sanitizer::uptr {}; } // namespace std DECLARE_REAL(void *, malloc, uptr size) @@ -38,6 +39,18 @@ DECLARE_REAL(void, free, void *ptr) invoke_malloc_hook(p, size); \ return p; +#define OPERATOR_NEW_BODY_ALIGN(mangled_name, nothrow) \ + if (cur_thread()->in_symbolizer) \ + return InternalAlloc(size, nullptr, (uptr)align); \ + void *p = 0; \ + { \ + SCOPED_INTERCEPTOR_RAW(mangled_name, size); \ + p = user_memalign(thr, pc, (uptr)align, size); \ + if (!nothrow && UNLIKELY(!p)) DieOnFailure::OnOOM(); \ + } \ + invoke_malloc_hook(p, size); \ + return p; + SANITIZER_INTERFACE_ATTRIBUTE void *operator new(__sanitizer::uptr size); void *operator new(__sanitizer::uptr size) { @@ -62,6 +75,36 @@ void *operator new[](__sanitizer::uptr size, std::nothrow_t const&) { OPERATOR_NEW_BODY(_ZnamRKSt9nothrow_t, true /*nothrow*/); } +SANITIZER_INTERFACE_ATTRIBUTE +void *operator new(__sanitizer::uptr size, std::align_val_t align); +void *operator new(__sanitizer::uptr size, std::align_val_t align) { + OPERATOR_NEW_BODY_ALIGN(_ZnwmSt11align_val_t, false /*nothrow*/); +} + +SANITIZER_INTERFACE_ATTRIBUTE +void *operator new[](__sanitizer::uptr size, std::align_val_t align); +void *operator new[](__sanitizer::uptr size, std::align_val_t align) { + OPERATOR_NEW_BODY_ALIGN(_ZnamSt11align_val_t, false /*nothrow*/); +} + +SANITIZER_INTERFACE_ATTRIBUTE +void *operator new(__sanitizer::uptr size, std::align_val_t align, + std::nothrow_t const&); +void *operator new(__sanitizer::uptr size, std::align_val_t align, + std::nothrow_t const&) { + OPERATOR_NEW_BODY_ALIGN(_ZnwmSt11align_val_tRKSt9nothrow_t, + true /*nothrow*/); +} + +SANITIZER_INTERFACE_ATTRIBUTE +void *operator new[](__sanitizer::uptr size, std::align_val_t align, + std::nothrow_t const&); +void *operator new[](__sanitizer::uptr size, std::align_val_t align, + std::nothrow_t const&) { + OPERATOR_NEW_BODY_ALIGN(_ZnamSt11align_val_tRKSt9nothrow_t, + true /*nothrow*/); +} + #define OPERATOR_DELETE_BODY(mangled_name) \ if (ptr == 0) return; \ if (cur_thread()->in_symbolizer) \ @@ -93,3 +136,57 @@ void operator delete[](void *ptr, std::nothrow_t const&); void operator delete[](void *ptr, std::nothrow_t const&) { OPERATOR_DELETE_BODY(_ZdaPvRKSt9nothrow_t); } + +SANITIZER_INTERFACE_ATTRIBUTE +void operator delete(void *ptr, __sanitizer::uptr size) NOEXCEPT; +void operator delete(void *ptr, __sanitizer::uptr size) NOEXCEPT { + OPERATOR_DELETE_BODY(_ZdlPvm); +} + +SANITIZER_INTERFACE_ATTRIBUTE +void operator delete[](void *ptr, __sanitizer::uptr size) NOEXCEPT; +void operator delete[](void *ptr, __sanitizer::uptr size) NOEXCEPT { + OPERATOR_DELETE_BODY(_ZdaPvm); +} + +SANITIZER_INTERFACE_ATTRIBUTE +void operator delete(void *ptr, std::align_val_t align) NOEXCEPT; +void operator delete(void *ptr, std::align_val_t align) NOEXCEPT { + OPERATOR_DELETE_BODY(_ZdlPvSt11align_val_t); +} + +SANITIZER_INTERFACE_ATTRIBUTE +void operator delete[](void *ptr, std::align_val_t align) NOEXCEPT; +void operator delete[](void *ptr, std::align_val_t align) NOEXCEPT { + OPERATOR_DELETE_BODY(_ZdaPvSt11align_val_t); +} + +SANITIZER_INTERFACE_ATTRIBUTE +void operator delete(void *ptr, std::align_val_t align, std::nothrow_t const&); +void operator delete(void *ptr, std::align_val_t align, std::nothrow_t const&) { + OPERATOR_DELETE_BODY(_ZdlPvSt11align_val_tRKSt9nothrow_t); +} + +SANITIZER_INTERFACE_ATTRIBUTE +void operator delete[](void *ptr, std::align_val_t align, + std::nothrow_t const&); +void operator delete[](void *ptr, std::align_val_t align, + std::nothrow_t const&) { + OPERATOR_DELETE_BODY(_ZdaPvSt11align_val_tRKSt9nothrow_t); +} + +SANITIZER_INTERFACE_ATTRIBUTE +void operator delete(void *ptr, __sanitizer::uptr size, + std::align_val_t align) NOEXCEPT; +void operator delete(void *ptr, __sanitizer::uptr size, + std::align_val_t align) NOEXCEPT { + OPERATOR_DELETE_BODY(_ZdlPvmSt11align_val_t); +} + +SANITIZER_INTERFACE_ATTRIBUTE +void operator delete[](void *ptr, __sanitizer::uptr size, + std::align_val_t align) NOEXCEPT; +void operator delete[](void *ptr, __sanitizer::uptr size, + std::align_val_t align) NOEXCEPT { + OPERATOR_DELETE_BODY(_ZdaPvmSt11align_val_t); +} diff --git a/compiler-rt/test/sanitizer_common/TestCases/Linux/new_delete_test.cc b/compiler-rt/test/sanitizer_common/TestCases/Linux/new_delete_test.cc new file mode 100644 index 0000000..5532da3 --- /dev/null +++ b/compiler-rt/test/sanitizer_common/TestCases/Linux/new_delete_test.cc @@ -0,0 +1,80 @@ +// RUN: %clangxx -std=c++1z -faligned-allocation -O0 %s -o %t && %run %t +// RUN: %clangxx -std=c++1z -faligned-allocation -fsized-deallocation -O0 %s -o %t && %run %t + +// ubsan does not intercept new/delete. +// UNSUPPORTED: ubsan + +// Check that all new/delete variants are defined and work with supported +// sanitizers. Sanitizer-specific failure modes tests are supposed to go to +// the particular sanitizier's test suites. + +#include <cstddef> + +// Define all new/delete to do not depend on the version provided by the +// plaform. The implementation is provided by the sanitizer anyway. + +namespace std { +struct nothrow_t {}; +static const nothrow_t nothrow; +enum class align_val_t : size_t {}; +} // namespace std + +void *operator new(size_t); +void *operator new[](size_t); +void *operator new(size_t, std::nothrow_t const&); +void *operator new[](size_t, std::nothrow_t const&); +void *operator new(size_t, std::align_val_t); +void *operator new[](size_t, std::align_val_t); +void *operator new(size_t, std::align_val_t, std::nothrow_t const&); +void *operator new[](size_t, std::align_val_t, std::nothrow_t const&); + +void operator delete(void*) throw(); +void operator delete[](void*) throw(); +void operator delete(void*, std::nothrow_t const&); +void operator delete[](void*, std::nothrow_t const&); +void operator delete(void*, size_t) throw(); +void operator delete[](void*, size_t) throw(); +void operator delete(void*, std::align_val_t) throw(); +void operator delete[](void*, std::align_val_t) throw(); +void operator delete(void*, std::align_val_t, std::nothrow_t const&); +void operator delete[](void*, std::align_val_t, std::nothrow_t const&); +void operator delete(void*, size_t, std::align_val_t) throw(); +void operator delete[](void*, size_t, std::align_val_t) throw(); + + +template<typename T> +inline T* break_optimization(T *arg) { + __asm__ __volatile__("" : : "r" (arg) : "memory"); + return arg; +} + + +struct S12 { int a, b, c; }; +struct alignas(128) S12_128 { int a, b, c; }; +struct alignas(256) S12_256 { int a, b, c; }; +struct alignas(512) S1024_512 { char a[1024]; }; +struct alignas(1024) S1024_1024 { char a[1024]; }; + + +int main(int argc, char **argv) { + delete break_optimization(new S12); + operator delete(break_optimization(new S12), std::nothrow); + delete [] break_optimization(new S12[100]); + operator delete[](break_optimization(new S12[100]), std::nothrow); + + delete break_optimization(new S12_128); + operator delete(break_optimization(new S12_128), + std::align_val_t(alignof(S12_128))); + operator delete(break_optimization(new S12_128), + std::align_val_t(alignof(S12_128)), std::nothrow); + operator delete(break_optimization(new S12_128), sizeof(S12_128), + std::align_val_t(alignof(S12_128))); + + delete [] break_optimization(new S12_128[100]); + operator delete[](break_optimization(new S12_128[100]), + std::align_val_t(alignof(S12_128))); + operator delete[](break_optimization(new S12_128[100]), + std::align_val_t(alignof(S12_128)), std::nothrow); + operator delete[](break_optimization(new S12_128[100]), sizeof(S12_128[100]), + std::align_val_t(alignof(S12_128))); +} |