diff --git a/compiler-rt/lib/gwp_asan/definitions.h b/compiler-rt/lib/gwp_asan/definitions.h index bec02903893462..c6785d4aba6952 100644 --- a/compiler-rt/lib/gwp_asan/definitions.h +++ b/compiler-rt/lib/gwp_asan/definitions.h @@ -12,7 +12,8 @@ #define GWP_ASAN_TLS_INITIAL_EXEC \ __thread __attribute__((tls_model("initial-exec"))) -#define GWP_ASAN_UNLIKELY(X) __builtin_expect(!!(X), 0) +#define GWP_ASAN_LIKELY(EXPR) __builtin_expect((bool)(EXPR), true) +#define GWP_ASAN_UNLIKELY(EXPR) __builtin_expect((bool)(EXPR), false) #define GWP_ASAN_ALWAYS_INLINE inline __attribute__((always_inline)) #define GWP_ASAN_WEAK __attribute__((weak)) diff --git a/compiler-rt/lib/gwp_asan/platform_specific/guarded_pool_allocator_fuchsia.cpp b/compiler-rt/lib/gwp_asan/platform_specific/guarded_pool_allocator_fuchsia.cpp index 3f39402652a998..5d5c729cdc8b70 100644 --- a/compiler-rt/lib/gwp_asan/platform_specific/guarded_pool_allocator_fuchsia.cpp +++ b/compiler-rt/lib/gwp_asan/platform_specific/guarded_pool_allocator_fuchsia.cpp @@ -24,13 +24,13 @@ void *GuardedPoolAllocator::map(size_t Size, const char *Name) const { assert((Size % State.PageSize) == 0); zx_handle_t Vmo; zx_status_t Status = _zx_vmo_create(Size, 0, &Vmo); - check(Status == ZX_OK, "Failed to create Vmo"); + checkWithErrorCode(Status == ZX_OK, "Failed to create Vmo", Status); _zx_object_set_property(Vmo, ZX_PROP_NAME, Name, strlen(Name)); zx_vaddr_t Addr; Status = _zx_vmar_map(_zx_vmar_root_self(), ZX_VM_PERM_READ | ZX_VM_PERM_WRITE | ZX_VM_ALLOW_FAULTS, 0, Vmo, 0, Size, &Addr); - check(Status == ZX_OK, "Vmo mapping failed"); + checkWithErrorCode(Status == ZX_OK, "Vmo mapping failed", Status); _zx_handle_close(Vmo); return reinterpret_cast(Addr); } @@ -40,7 +40,7 @@ void GuardedPoolAllocator::unmap(void *Ptr, size_t Size) const { assert((Size % State.PageSize) == 0); zx_status_t Status = _zx_vmar_unmap(_zx_vmar_root_self(), reinterpret_cast(Ptr), Size); - check(Status == ZX_OK, "Vmo unmapping failed"); + checkWithErrorCode(Status == ZX_OK, "Vmo unmapping failed", Status); } void *GuardedPoolAllocator::reserveGuardedPool(size_t Size) { @@ -50,7 +50,8 @@ void *GuardedPoolAllocator::reserveGuardedPool(size_t Size) { _zx_vmar_root_self(), ZX_VM_CAN_MAP_READ | ZX_VM_CAN_MAP_WRITE | ZX_VM_CAN_MAP_SPECIFIC, 0, Size, &GuardedPagePoolPlatformData.Vmar, &Addr); - check(Status == ZX_OK, "Failed to reserve guarded pool allocator memory"); + checkWithErrorCode(Status == ZX_OK, + "Failed to reserve guarded pool allocator memory", Status); _zx_object_set_property(GuardedPagePoolPlatformData.Vmar, ZX_PROP_NAME, kGwpAsanGuardPageName, strlen(kGwpAsanGuardPageName)); return reinterpret_cast(Addr); @@ -59,8 +60,10 @@ void *GuardedPoolAllocator::reserveGuardedPool(size_t Size) { void GuardedPoolAllocator::unreserveGuardedPool() { const zx_handle_t Vmar = GuardedPagePoolPlatformData.Vmar; assert(Vmar != ZX_HANDLE_INVALID && Vmar != _zx_vmar_root_self()); - check(_zx_vmar_destroy(Vmar) == ZX_OK, "Failed to destroy a vmar"); - check(_zx_handle_close(Vmar) == ZX_OK, "Failed to close a vmar"); + zx_status_t Status = _zx_vmar_destroy(Vmar); + checkWithErrorCode(Status == ZX_OK, "Failed to destroy a vmar", Status); + Status = _zx_handle_close(Vmar); + checkWithErrorCode(Status == ZX_OK, "Failed to close a vmar", Status); GuardedPagePoolPlatformData.Vmar = ZX_HANDLE_INVALID; } @@ -69,7 +72,7 @@ void GuardedPoolAllocator::allocateInGuardedPool(void *Ptr, size_t Size) const { assert((Size % State.PageSize) == 0); zx_handle_t Vmo; zx_status_t Status = _zx_vmo_create(Size, 0, &Vmo); - check(Status == ZX_OK, "Failed to create vmo"); + checkWithErrorCode(Status == ZX_OK, "Failed to create vmo", Status); _zx_object_set_property(Vmo, ZX_PROP_NAME, kGwpAsanAliveSlotName, strlen(kGwpAsanAliveSlotName)); const zx_handle_t Vmar = GuardedPagePoolPlatformData.Vmar; @@ -81,7 +84,7 @@ void GuardedPoolAllocator::allocateInGuardedPool(void *Ptr, size_t Size) const { ZX_VM_PERM_READ | ZX_VM_PERM_WRITE | ZX_VM_ALLOW_FAULTS | ZX_VM_SPECIFIC, Offset, Vmo, 0, Size, &P); - check(Status == ZX_OK, "Vmo mapping failed"); + checkWithErrorCode(Status == ZX_OK, "Vmo mapping failed", Status); _zx_handle_close(Vmo); } @@ -93,7 +96,7 @@ void GuardedPoolAllocator::deallocateInGuardedPool(void *Ptr, assert(Vmar != ZX_HANDLE_INVALID && Vmar != _zx_vmar_root_self()); const zx_status_t Status = _zx_vmar_unmap(Vmar, reinterpret_cast(Ptr), Size); - check(Status == ZX_OK, "Vmar unmapping failed"); + checkWithErrorCode(Status == ZX_OK, "Vmar unmapping failed", Status); } size_t GuardedPoolAllocator::getPlatformPageSize() { diff --git a/compiler-rt/lib/gwp_asan/platform_specific/guarded_pool_allocator_posix.cpp b/compiler-rt/lib/gwp_asan/platform_specific/guarded_pool_allocator_posix.cpp index 549e31acb176d3..7b2e19956c7962 100644 --- a/compiler-rt/lib/gwp_asan/platform_specific/guarded_pool_allocator_posix.cpp +++ b/compiler-rt/lib/gwp_asan/platform_specific/guarded_pool_allocator_posix.cpp @@ -12,6 +12,7 @@ #include "gwp_asan/utilities.h" #include +#include #include #include #include @@ -46,7 +47,8 @@ void *GuardedPoolAllocator::map(size_t Size, const char *Name) const { assert((Size % State.PageSize) == 0); void *Ptr = mmap(nullptr, Size, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); - check(Ptr != MAP_FAILED, "Failed to map guarded pool allocator memory"); + checkWithErrorCode(Ptr != MAP_FAILED, + "Failed to map guarded pool allocator memory", errno); MaybeSetMappingName(Ptr, Size, Name); return Ptr; } @@ -54,15 +56,16 @@ void *GuardedPoolAllocator::map(size_t Size, const char *Name) const { void GuardedPoolAllocator::unmap(void *Ptr, size_t Size) const { assert((reinterpret_cast(Ptr) % State.PageSize) == 0); assert((Size % State.PageSize) == 0); - check(munmap(Ptr, Size) == 0, - "Failed to unmap guarded pool allocator memory."); + checkWithErrorCode(munmap(Ptr, Size) == 0, + "Failed to unmap guarded pool allocator memory.", errno); } void *GuardedPoolAllocator::reserveGuardedPool(size_t Size) { assert((Size % State.PageSize) == 0); void *Ptr = mmap(nullptr, Size, PROT_NONE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); - check(Ptr != MAP_FAILED, "Failed to reserve guarded pool allocator memory"); + checkWithErrorCode(Ptr != MAP_FAILED, + "Failed to reserve guarded pool allocator memory", errno); MaybeSetMappingName(Ptr, Size, kGwpAsanGuardPageName); return Ptr; } @@ -75,8 +78,9 @@ void GuardedPoolAllocator::unreserveGuardedPool() { void GuardedPoolAllocator::allocateInGuardedPool(void *Ptr, size_t Size) const { assert((reinterpret_cast(Ptr) % State.PageSize) == 0); assert((Size % State.PageSize) == 0); - check(mprotect(Ptr, Size, PROT_READ | PROT_WRITE) == 0, - "Failed to allocate in guarded pool allocator memory"); + checkWithErrorCode(mprotect(Ptr, Size, PROT_READ | PROT_WRITE) == 0, + "Failed to allocate in guarded pool allocator memory", + errno); MaybeSetMappingName(Ptr, Size, kGwpAsanAliveSlotName); } @@ -87,9 +91,10 @@ void GuardedPoolAllocator::deallocateInGuardedPool(void *Ptr, // mmap() a PROT_NONE page over the address to release it to the system, if // we used mprotect() here the system would count pages in the quarantine // against the RSS. - check(mmap(Ptr, Size, PROT_NONE, MAP_FIXED | MAP_ANONYMOUS | MAP_PRIVATE, -1, - 0) != MAP_FAILED, - "Failed to deallocate in guarded pool allocator memory"); + checkWithErrorCode( + mmap(Ptr, Size, PROT_NONE, MAP_FIXED | MAP_ANONYMOUS | MAP_PRIVATE, -1, + 0) != MAP_FAILED, + "Failed to deallocate in guarded pool allocator memory", errno); MaybeSetMappingName(Ptr, Size, kGwpAsanGuardPageName); } diff --git a/compiler-rt/lib/gwp_asan/platform_specific/utilities_fuchsia.cpp b/compiler-rt/lib/gwp_asan/platform_specific/utilities_fuchsia.cpp index bc9d3a4462a2f7..fecf94b0d1a196 100644 --- a/compiler-rt/lib/gwp_asan/platform_specific/utilities_fuchsia.cpp +++ b/compiler-rt/lib/gwp_asan/platform_specific/utilities_fuchsia.cpp @@ -8,12 +8,25 @@ #include "gwp_asan/utilities.h" +#include +#include #include #include +#include namespace gwp_asan { void die(const char *Message) { __sanitizer_log_write(Message, strlen(Message)); __builtin_trap(); } + +void dieWithErrorCode(const char *Message, int64_t ErrorCode) { + const char *error_str = + _zx_status_get_string(static_cast(ErrorCode)); + size_t buffer_size = strlen(Message) + 32 + strlen(error_str); + char *buffer = static_cast(alloca(buffer_size)); + snprintf(buffer, buffer_size, "%s (Error Code: %s)", Message, error_str); + __sanitizer_log_write(buffer, strlen(buffer)); + __builtin_trap(); +} } // namespace gwp_asan diff --git a/compiler-rt/lib/gwp_asan/platform_specific/utilities_posix.cpp b/compiler-rt/lib/gwp_asan/platform_specific/utilities_posix.cpp index 73579630550956..750198062ce4f5 100644 --- a/compiler-rt/lib/gwp_asan/platform_specific/utilities_posix.cpp +++ b/compiler-rt/lib/gwp_asan/platform_specific/utilities_posix.cpp @@ -6,7 +6,11 @@ // //===----------------------------------------------------------------------===// +#include #include // IWYU pragma: keep (for __BIONIC__ macro) +#include +#include +#include #ifdef __BIONIC__ #include "gwp_asan/definitions.h" @@ -27,4 +31,21 @@ void die(const char *Message) { __builtin_trap(); #endif // __BIONIC__ } + +void dieWithErrorCode(const char *Message, int64_t ErrorCode) { +#ifdef __BIONIC__ + if (&android_set_abort_message == nullptr) + abort(); + + size_t buffer_size = strlen(Message) + 48; + char *buffer = static_cast(alloca(buffer_size)); + snprintf(buffer, buffer_size, "%s (Error Code: %" PRId64 ")", Message, + ErrorCode); + android_set_abort_message(buffer); + abort(); +#else // __BIONIC__ + fprintf(stderr, "%s (Error Code: %" PRId64 ")", Message, ErrorCode); + __builtin_trap(); +#endif // __BIONIC__ +} } // namespace gwp_asan diff --git a/compiler-rt/lib/gwp_asan/tests/CMakeLists.txt b/compiler-rt/lib/gwp_asan/tests/CMakeLists.txt index ca43ec2a94ac4d..5de1af10eec366 100644 --- a/compiler-rt/lib/gwp_asan/tests/CMakeLists.txt +++ b/compiler-rt/lib/gwp_asan/tests/CMakeLists.txt @@ -28,7 +28,9 @@ set(GWP_ASAN_UNITTESTS late_init.cpp options.cpp recoverable.cpp - never_allocated.cpp) + never_allocated.cpp + utilities.cpp +) set(GWP_ASAN_UNIT_TEST_HEADERS ${GWP_ASAN_HEADERS} diff --git a/compiler-rt/lib/gwp_asan/tests/utilities.cpp b/compiler-rt/lib/gwp_asan/tests/utilities.cpp new file mode 100644 index 00000000000000..09a54e526f5dbc --- /dev/null +++ b/compiler-rt/lib/gwp_asan/tests/utilities.cpp @@ -0,0 +1,24 @@ +//===-- utilities.cpp -------------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "gwp_asan/utilities.h" +#include "gwp_asan/tests/harness.h" + +using gwp_asan::check; +using gwp_asan::checkWithErrorCode; + +TEST(UtilitiesDeathTest, CheckPrintsAsExpected) { + EXPECT_DEATH({ check(false, "Hello world"); }, "Hello world"); + check(true, "Should not crash"); + EXPECT_DEATH( + { checkWithErrorCode(false, "Hello world", 1337); }, + "Hello world \\(Error Code: 1337\\)"); + EXPECT_DEATH( + { checkWithErrorCode(false, "Hello world", -1337); }, + "Hello world \\(Error Code: -1337\\)"); +} diff --git a/compiler-rt/lib/gwp_asan/utilities.h b/compiler-rt/lib/gwp_asan/utilities.h index 76e5df2e3eb8f8..02f450a9eeec3d 100644 --- a/compiler-rt/lib/gwp_asan/utilities.h +++ b/compiler-rt/lib/gwp_asan/utilities.h @@ -12,17 +12,28 @@ #include "gwp_asan/definitions.h" #include +#include namespace gwp_asan { // Terminates in a platform-specific way with `Message`. void die(const char *Message); +void dieWithErrorCode(const char *Message, int64_t ErrorCode); // Checks that `Condition` is true, otherwise dies with `Message`. GWP_ASAN_ALWAYS_INLINE void check(bool Condition, const char *Message) { - if (Condition) + if (GWP_ASAN_LIKELY(Condition)) return; die(Message); } + +// Checks that `Condition` is true, otherwise dies with `Message` (including +// errno at the end). +GWP_ASAN_ALWAYS_INLINE void +checkWithErrorCode(bool Condition, const char *Message, int64_t ErrorCode) { + if (GWP_ASAN_LIKELY(Condition)) + return; + dieWithErrorCode(Message, ErrorCode); +} } // namespace gwp_asan #endif // GWP_ASAN_UTILITIES_H_