1 | //===-- crash_handler.h -----------------------------------------*- 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 | // This file contains interface functions that can be called by an in-process or |
10 | // out-of-process crash handler after the process has terminated. Functions in |
11 | // this interface are never thread safe. For an in-process crash handler, the |
12 | // handler should call GuardedPoolAllocator::disable() to stop any other threads |
13 | // from retrieving new GWP-ASan allocations, which may corrupt the metadata. |
14 | #ifndef GWP_ASAN_INTERFACE_H_ |
15 | #define GWP_ASAN_INTERFACE_H_ |
16 | |
17 | #include "gwp_asan/common.h" |
18 | |
19 | #ifdef __cplusplus |
20 | extern "C" { |
21 | #endif |
22 | |
23 | // When a process crashes, there are three possible outcomes: |
24 | // 1. The crash is unrelated to GWP-ASan - in which case this function returns |
25 | // false. |
26 | // 2. The crash is internally detected within GWP-ASan itself (e.g. a |
27 | // double-free bug is caught in GuardedPoolAllocator::deallocate(), and |
28 | // GWP-ASan will terminate the process). In this case - this function |
29 | // returns true. |
30 | // 3. The crash is caused by a memory error at `AccessPtr` that's caught by the |
31 | // system, but GWP-ASan is responsible for the allocation. In this case - |
32 | // the function also returns true. |
33 | // This function takes an optional `AccessPtr` parameter. If the pointer that |
34 | // was attempted to be accessed is available, you should provide it here. In the |
35 | // case of some internally-detected errors, the crash may manifest as an abort |
36 | // or trap may or may not have an associated pointer. In these cases, the |
37 | // pointer can be obtained by a call to __gwp_asan_get_internal_crash_address. |
38 | bool __gwp_asan_error_is_mine(const gwp_asan::AllocatorState *State, |
39 | uintptr_t ErrorPtr = 0u); |
40 | |
41 | // Diagnose and return the type of error that occurred at `ErrorPtr`. If |
42 | // `ErrorPtr` is unrelated to GWP-ASan, or if the error type cannot be deduced, |
43 | // this function returns Error::UNKNOWN. |
44 | gwp_asan::Error |
45 | __gwp_asan_diagnose_error(const gwp_asan::AllocatorState *State, |
46 | const gwp_asan::AllocationMetadata *Metadata, |
47 | uintptr_t ErrorPtr); |
48 | |
49 | // This function, provided the fault address from the signal handler, returns |
50 | // the following values: |
51 | // 1. If the crash was caused by an internally-detected error (invalid free, |
52 | // double free), this function returns the pointer that was used for the |
53 | // internally-detected bad operation (i.e. the pointer given to free()). |
54 | // 2. For externally-detected crashes (use-after-free, buffer-overflow), this |
55 | // function returns zero. |
56 | // 3. If GWP-ASan wasn't responsible for the crash at all, this function also |
57 | // returns zero. |
58 | uintptr_t |
59 | __gwp_asan_get_internal_crash_address(const gwp_asan::AllocatorState *State, |
60 | uintptr_t ErrorPtr); |
61 | |
62 | // Returns a pointer to the metadata for the allocation that's responsible for |
63 | // the crash. This metadata should not be dereferenced directly due to API |
64 | // compatibility issues, but should be instead passed to functions below for |
65 | // information retrieval. Returns nullptr if there is no metadata available for |
66 | // this crash. |
67 | const gwp_asan::AllocationMetadata * |
68 | __gwp_asan_get_metadata(const gwp_asan::AllocatorState *State, |
69 | const gwp_asan::AllocationMetadata *Metadata, |
70 | uintptr_t ErrorPtr); |
71 | |
72 | // +---------------------------------------------------------------------------+ |
73 | // | Error Information Functions | |
74 | // +---------------------------------------------------------------------------+ |
75 | // Functions below return information about the type of error that was caught by |
76 | // GWP-ASan, or information about the allocation that caused the error. These |
77 | // functions generally take an `AllocationMeta` argument, which should be |
78 | // retrieved via. __gwp_asan_get_metadata. |
79 | |
80 | // Returns the start of the allocation whose metadata is in `AllocationMeta`. |
81 | uintptr_t __gwp_asan_get_allocation_address( |
82 | const gwp_asan::AllocationMetadata *AllocationMeta); |
83 | |
84 | // Returns the size of the allocation whose metadata is in `AllocationMeta` |
85 | size_t __gwp_asan_get_allocation_size( |
86 | const gwp_asan::AllocationMetadata *AllocationMeta); |
87 | |
88 | // Returns the Thread ID that allocated the memory that caused the error at |
89 | // `ErrorPtr`. This function may not be called if __gwp_asan_has_metadata() |
90 | // returns false. |
91 | uint64_t __gwp_asan_get_allocation_thread_id( |
92 | const gwp_asan::AllocationMetadata *AllocationMeta); |
93 | |
94 | // Retrieve the allocation trace for the allocation whose metadata is in |
95 | // `AllocationMeta`, and place it into the provided `Buffer` that has at least |
96 | // `BufferLen` elements. This function returns the number of frames that would |
97 | // have been written into `Buffer` if the space was available (i.e. however many |
98 | // frames were stored by GWP-ASan). A return value greater than `BufferLen` |
99 | // indicates that the trace was truncated when storing to `Buffer`. |
100 | size_t __gwp_asan_get_allocation_trace( |
101 | const gwp_asan::AllocationMetadata *AllocationMeta, uintptr_t *Buffer, |
102 | size_t BufferLen); |
103 | |
104 | // Returns whether the allocation whose metadata is in `AllocationMeta` has been |
105 | // deallocated. This function may not be called if __gwp_asan_has_metadata() |
106 | // returns false. |
107 | bool __gwp_asan_is_deallocated( |
108 | const gwp_asan::AllocationMetadata *AllocationMeta); |
109 | |
110 | // Returns the Thread ID that deallocated the memory whose metadata is in |
111 | // `AllocationMeta`. This function may not be called if |
112 | // __gwp_asan_is_deallocated() returns false. |
113 | uint64_t __gwp_asan_get_deallocation_thread_id( |
114 | const gwp_asan::AllocationMetadata *AllocationMeta); |
115 | |
116 | // Retrieve the deallocation trace for the allocation whose metadata is in |
117 | // `AllocationMeta`, and place it into the provided `Buffer` that has at least |
118 | // `BufferLen` elements. This function returns the number of frames that would |
119 | // have been written into `Buffer` if the space was available (i.e. however many |
120 | // frames were stored by GWP-ASan). A return value greater than `BufferLen` |
121 | // indicates that the trace was truncated when storing to `Buffer`. This |
122 | // function may not be called if __gwp_asan_is_deallocated() returns false. |
123 | size_t __gwp_asan_get_deallocation_trace( |
124 | const gwp_asan::AllocationMetadata *AllocationMeta, uintptr_t *Buffer, |
125 | size_t BufferLen); |
126 | |
127 | #ifdef __cplusplus |
128 | } // extern "C" |
129 | #endif |
130 | |
131 | #endif // GWP_ASAN_INTERFACE_H_ |
132 | |