Skip to content

Commit 0a94511

Browse files
authored
Log errno (or fuchsia equivalent) on map failures (#95391)
A feature requested by Android, we should log errno (or the corresponding fuchsia error status) as part of the message when mmap/mprotect/etc. fails.
1 parent 46ecd7b commit 0a94511

8 files changed

+101
-21
lines changed

compiler-rt/lib/gwp_asan/definitions.h

+2-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,8 @@
1212
#define GWP_ASAN_TLS_INITIAL_EXEC \
1313
__thread __attribute__((tls_model("initial-exec")))
1414

15-
#define GWP_ASAN_UNLIKELY(X) __builtin_expect(!!(X), 0)
15+
#define GWP_ASAN_LIKELY(EXPR) __builtin_expect((bool)(EXPR), true)
16+
#define GWP_ASAN_UNLIKELY(EXPR) __builtin_expect((bool)(EXPR), false)
1617
#define GWP_ASAN_ALWAYS_INLINE inline __attribute__((always_inline))
1718

1819
#define GWP_ASAN_WEAK __attribute__((weak))

compiler-rt/lib/gwp_asan/platform_specific/guarded_pool_allocator_fuchsia.cpp

+12-9
Original file line numberDiff line numberDiff line change
@@ -24,13 +24,13 @@ void *GuardedPoolAllocator::map(size_t Size, const char *Name) const {
2424
assert((Size % State.PageSize) == 0);
2525
zx_handle_t Vmo;
2626
zx_status_t Status = _zx_vmo_create(Size, 0, &Vmo);
27-
check(Status == ZX_OK, "Failed to create Vmo");
27+
checkWithErrorCode(Status == ZX_OK, "Failed to create Vmo", Status);
2828
_zx_object_set_property(Vmo, ZX_PROP_NAME, Name, strlen(Name));
2929
zx_vaddr_t Addr;
3030
Status = _zx_vmar_map(_zx_vmar_root_self(),
3131
ZX_VM_PERM_READ | ZX_VM_PERM_WRITE | ZX_VM_ALLOW_FAULTS,
3232
0, Vmo, 0, Size, &Addr);
33-
check(Status == ZX_OK, "Vmo mapping failed");
33+
checkWithErrorCode(Status == ZX_OK, "Vmo mapping failed", Status);
3434
_zx_handle_close(Vmo);
3535
return reinterpret_cast<void *>(Addr);
3636
}
@@ -40,7 +40,7 @@ void GuardedPoolAllocator::unmap(void *Ptr, size_t Size) const {
4040
assert((Size % State.PageSize) == 0);
4141
zx_status_t Status = _zx_vmar_unmap(_zx_vmar_root_self(),
4242
reinterpret_cast<zx_vaddr_t>(Ptr), Size);
43-
check(Status == ZX_OK, "Vmo unmapping failed");
43+
checkWithErrorCode(Status == ZX_OK, "Vmo unmapping failed", Status);
4444
}
4545

4646
void *GuardedPoolAllocator::reserveGuardedPool(size_t Size) {
@@ -50,7 +50,8 @@ void *GuardedPoolAllocator::reserveGuardedPool(size_t Size) {
5050
_zx_vmar_root_self(),
5151
ZX_VM_CAN_MAP_READ | ZX_VM_CAN_MAP_WRITE | ZX_VM_CAN_MAP_SPECIFIC, 0,
5252
Size, &GuardedPagePoolPlatformData.Vmar, &Addr);
53-
check(Status == ZX_OK, "Failed to reserve guarded pool allocator memory");
53+
checkWithErrorCode(Status == ZX_OK,
54+
"Failed to reserve guarded pool allocator memory", Status);
5455
_zx_object_set_property(GuardedPagePoolPlatformData.Vmar, ZX_PROP_NAME,
5556
kGwpAsanGuardPageName, strlen(kGwpAsanGuardPageName));
5657
return reinterpret_cast<void *>(Addr);
@@ -59,8 +60,10 @@ void *GuardedPoolAllocator::reserveGuardedPool(size_t Size) {
5960
void GuardedPoolAllocator::unreserveGuardedPool() {
6061
const zx_handle_t Vmar = GuardedPagePoolPlatformData.Vmar;
6162
assert(Vmar != ZX_HANDLE_INVALID && Vmar != _zx_vmar_root_self());
62-
check(_zx_vmar_destroy(Vmar) == ZX_OK, "Failed to destroy a vmar");
63-
check(_zx_handle_close(Vmar) == ZX_OK, "Failed to close a vmar");
63+
zx_status_t Status = _zx_vmar_destroy(Vmar);
64+
checkWithErrorCode(Status == ZX_OK, "Failed to destroy a vmar", Status);
65+
Status = _zx_handle_close(Vmar);
66+
checkWithErrorCode(Status == ZX_OK, "Failed to close a vmar", Status);
6467
GuardedPagePoolPlatformData.Vmar = ZX_HANDLE_INVALID;
6568
}
6669

@@ -69,7 +72,7 @@ void GuardedPoolAllocator::allocateInGuardedPool(void *Ptr, size_t Size) const {
6972
assert((Size % State.PageSize) == 0);
7073
zx_handle_t Vmo;
7174
zx_status_t Status = _zx_vmo_create(Size, 0, &Vmo);
72-
check(Status == ZX_OK, "Failed to create vmo");
75+
checkWithErrorCode(Status == ZX_OK, "Failed to create vmo", Status);
7376
_zx_object_set_property(Vmo, ZX_PROP_NAME, kGwpAsanAliveSlotName,
7477
strlen(kGwpAsanAliveSlotName));
7578
const zx_handle_t Vmar = GuardedPagePoolPlatformData.Vmar;
@@ -81,7 +84,7 @@ void GuardedPoolAllocator::allocateInGuardedPool(void *Ptr, size_t Size) const {
8184
ZX_VM_PERM_READ | ZX_VM_PERM_WRITE |
8285
ZX_VM_ALLOW_FAULTS | ZX_VM_SPECIFIC,
8386
Offset, Vmo, 0, Size, &P);
84-
check(Status == ZX_OK, "Vmo mapping failed");
87+
checkWithErrorCode(Status == ZX_OK, "Vmo mapping failed", Status);
8588
_zx_handle_close(Vmo);
8689
}
8790

@@ -93,7 +96,7 @@ void GuardedPoolAllocator::deallocateInGuardedPool(void *Ptr,
9396
assert(Vmar != ZX_HANDLE_INVALID && Vmar != _zx_vmar_root_self());
9497
const zx_status_t Status =
9598
_zx_vmar_unmap(Vmar, reinterpret_cast<zx_vaddr_t>(Ptr), Size);
96-
check(Status == ZX_OK, "Vmar unmapping failed");
99+
checkWithErrorCode(Status == ZX_OK, "Vmar unmapping failed", Status);
97100
}
98101

99102
size_t GuardedPoolAllocator::getPlatformPageSize() {

compiler-rt/lib/gwp_asan/platform_specific/guarded_pool_allocator_posix.cpp

+14-9
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#include "gwp_asan/utilities.h"
1313

1414
#include <assert.h>
15+
#include <errno.h>
1516
#include <pthread.h>
1617
#include <stdint.h>
1718
#include <stdlib.h>
@@ -46,23 +47,25 @@ void *GuardedPoolAllocator::map(size_t Size, const char *Name) const {
4647
assert((Size % State.PageSize) == 0);
4748
void *Ptr = mmap(nullptr, Size, PROT_READ | PROT_WRITE,
4849
MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
49-
check(Ptr != MAP_FAILED, "Failed to map guarded pool allocator memory");
50+
checkWithErrorCode(Ptr != MAP_FAILED,
51+
"Failed to map guarded pool allocator memory", errno);
5052
MaybeSetMappingName(Ptr, Size, Name);
5153
return Ptr;
5254
}
5355

5456
void GuardedPoolAllocator::unmap(void *Ptr, size_t Size) const {
5557
assert((reinterpret_cast<uintptr_t>(Ptr) % State.PageSize) == 0);
5658
assert((Size % State.PageSize) == 0);
57-
check(munmap(Ptr, Size) == 0,
58-
"Failed to unmap guarded pool allocator memory.");
59+
checkWithErrorCode(munmap(Ptr, Size) == 0,
60+
"Failed to unmap guarded pool allocator memory.", errno);
5961
}
6062

6163
void *GuardedPoolAllocator::reserveGuardedPool(size_t Size) {
6264
assert((Size % State.PageSize) == 0);
6365
void *Ptr =
6466
mmap(nullptr, Size, PROT_NONE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
65-
check(Ptr != MAP_FAILED, "Failed to reserve guarded pool allocator memory");
67+
checkWithErrorCode(Ptr != MAP_FAILED,
68+
"Failed to reserve guarded pool allocator memory", errno);
6669
MaybeSetMappingName(Ptr, Size, kGwpAsanGuardPageName);
6770
return Ptr;
6871
}
@@ -75,8 +78,9 @@ void GuardedPoolAllocator::unreserveGuardedPool() {
7578
void GuardedPoolAllocator::allocateInGuardedPool(void *Ptr, size_t Size) const {
7679
assert((reinterpret_cast<uintptr_t>(Ptr) % State.PageSize) == 0);
7780
assert((Size % State.PageSize) == 0);
78-
check(mprotect(Ptr, Size, PROT_READ | PROT_WRITE) == 0,
79-
"Failed to allocate in guarded pool allocator memory");
81+
checkWithErrorCode(mprotect(Ptr, Size, PROT_READ | PROT_WRITE) == 0,
82+
"Failed to allocate in guarded pool allocator memory",
83+
errno);
8084
MaybeSetMappingName(Ptr, Size, kGwpAsanAliveSlotName);
8185
}
8286

@@ -87,9 +91,10 @@ void GuardedPoolAllocator::deallocateInGuardedPool(void *Ptr,
8791
// mmap() a PROT_NONE page over the address to release it to the system, if
8892
// we used mprotect() here the system would count pages in the quarantine
8993
// against the RSS.
90-
check(mmap(Ptr, Size, PROT_NONE, MAP_FIXED | MAP_ANONYMOUS | MAP_PRIVATE, -1,
91-
0) != MAP_FAILED,
92-
"Failed to deallocate in guarded pool allocator memory");
94+
checkWithErrorCode(
95+
mmap(Ptr, Size, PROT_NONE, MAP_FIXED | MAP_ANONYMOUS | MAP_PRIVATE, -1,
96+
0) != MAP_FAILED,
97+
"Failed to deallocate in guarded pool allocator memory", errno);
9398
MaybeSetMappingName(Ptr, Size, kGwpAsanGuardPageName);
9499
}
95100

compiler-rt/lib/gwp_asan/platform_specific/utilities_fuchsia.cpp

+13
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,25 @@
88

99
#include "gwp_asan/utilities.h"
1010

11+
#include <alloca.h>
12+
#include <stdio.h>
1113
#include <string.h>
1214
#include <zircon/sanitizer.h>
15+
#include <zircon/status.h>
1316

1417
namespace gwp_asan {
1518
void die(const char *Message) {
1619
__sanitizer_log_write(Message, strlen(Message));
1720
__builtin_trap();
1821
}
22+
23+
void dieWithErrorCode(const char *Message, int64_t ErrorCode) {
24+
const char *error_str =
25+
_zx_status_get_string(static_cast<zx_status_t>(ErrorCode));
26+
size_t buffer_size = strlen(Message) + 32 + strlen(error_str);
27+
char *buffer = static_cast<char *>(alloca(buffer_size));
28+
snprintf(buffer, buffer_size, "%s (Error Code: %s)", Message, error_str);
29+
__sanitizer_log_write(buffer, strlen(buffer));
30+
__builtin_trap();
31+
}
1932
} // namespace gwp_asan

compiler-rt/lib/gwp_asan/platform_specific/utilities_posix.cpp

+21
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,11 @@
66
//
77
//===----------------------------------------------------------------------===//
88

9+
#include <alloca.h>
910
#include <features.h> // IWYU pragma: keep (for __BIONIC__ macro)
11+
#include <inttypes.h>
12+
#include <stdint.h>
13+
#include <string.h>
1014

1115
#ifdef __BIONIC__
1216
#include "gwp_asan/definitions.h"
@@ -27,4 +31,21 @@ void die(const char *Message) {
2731
__builtin_trap();
2832
#endif // __BIONIC__
2933
}
34+
35+
void dieWithErrorCode(const char *Message, int64_t ErrorCode) {
36+
#ifdef __BIONIC__
37+
if (&android_set_abort_message == nullptr)
38+
abort();
39+
40+
size_t buffer_size = strlen(Message) + 48;
41+
char *buffer = static_cast<char *>(alloca(buffer_size));
42+
snprintf(buffer, buffer_size, "%s (Error Code: %" PRId64 ")", Message,
43+
ErrorCode);
44+
android_set_abort_message(buffer);
45+
abort();
46+
#else // __BIONIC__
47+
fprintf(stderr, "%s (Error Code: %" PRId64 ")", Message, ErrorCode);
48+
__builtin_trap();
49+
#endif // __BIONIC__
50+
}
3051
} // namespace gwp_asan

compiler-rt/lib/gwp_asan/tests/CMakeLists.txt

+3-1
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,9 @@ set(GWP_ASAN_UNITTESTS
2828
late_init.cpp
2929
options.cpp
3030
recoverable.cpp
31-
never_allocated.cpp)
31+
never_allocated.cpp
32+
utilities.cpp
33+
)
3234

3335
set(GWP_ASAN_UNIT_TEST_HEADERS
3436
${GWP_ASAN_HEADERS}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
//===-- utilities.cpp -------------------------------------------*- C++ -*-===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#include "gwp_asan/utilities.h"
10+
#include "gwp_asan/tests/harness.h"
11+
12+
using gwp_asan::check;
13+
using gwp_asan::checkWithErrorCode;
14+
15+
TEST(UtilitiesDeathTest, CheckPrintsAsExpected) {
16+
EXPECT_DEATH({ check(false, "Hello world"); }, "Hello world");
17+
check(true, "Should not crash");
18+
EXPECT_DEATH(
19+
{ checkWithErrorCode(false, "Hello world", 1337); },
20+
"Hello world \\(Error Code: 1337\\)");
21+
EXPECT_DEATH(
22+
{ checkWithErrorCode(false, "Hello world", -1337); },
23+
"Hello world \\(Error Code: -1337\\)");
24+
}

compiler-rt/lib/gwp_asan/utilities.h

+12-1
Original file line numberDiff line numberDiff line change
@@ -12,17 +12,28 @@
1212
#include "gwp_asan/definitions.h"
1313

1414
#include <stddef.h>
15+
#include <stdint.h>
1516

1617
namespace gwp_asan {
1718
// Terminates in a platform-specific way with `Message`.
1819
void die(const char *Message);
20+
void dieWithErrorCode(const char *Message, int64_t ErrorCode);
1921

2022
// Checks that `Condition` is true, otherwise dies with `Message`.
2123
GWP_ASAN_ALWAYS_INLINE void check(bool Condition, const char *Message) {
22-
if (Condition)
24+
if (GWP_ASAN_LIKELY(Condition))
2325
return;
2426
die(Message);
2527
}
28+
29+
// Checks that `Condition` is true, otherwise dies with `Message` (including
30+
// errno at the end).
31+
GWP_ASAN_ALWAYS_INLINE void
32+
checkWithErrorCode(bool Condition, const char *Message, int64_t ErrorCode) {
33+
if (GWP_ASAN_LIKELY(Condition))
34+
return;
35+
dieWithErrorCode(Message, ErrorCode);
36+
}
2637
} // namespace gwp_asan
2738

2839
#endif // GWP_ASAN_UTILITIES_H_

0 commit comments

Comments
 (0)