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
20extern "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.
38bool __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.
44gwp_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.
58uintptr_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.
67const 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`.
81uintptr_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`
85size_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.
91uint64_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`.
100size_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.
107bool __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.
113uint64_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.
123size_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