1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
//===----------------------------------------------------------------------===//
//
// 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
//
//===----------------------------------------------------------------------===//
// TODO(LLVM 23): Remove this. We're making these an error to catch folks who might not have migrated.
// Since hardening went through several changes (many of which impacted user-facing macros),
// we're keeping these checks around for a bit longer than usual. Failure to properly configure
// hardening results in checks being dropped silently, which is a pretty big deal.
// The library provides the macro `_LIBCPP_HARDENING_MODE` which can be set to one of the following values:
//
// - `_LIBCPP_HARDENING_MODE_NONE`;
// - `_LIBCPP_HARDENING_MODE_FAST`;
// - `_LIBCPP_HARDENING_MODE_EXTENSIVE`;
// - `_LIBCPP_HARDENING_MODE_DEBUG`.
//
// These values have the following effects:
//
// - `_LIBCPP_HARDENING_MODE_NONE` -- sets the hardening mode to "none" which disables all runtime hardening checks;
//
// - `_LIBCPP_HARDENING_MODE_FAST` -- sets that hardening mode to "fast". The fast mode enables security-critical checks
// that can be done with relatively little runtime overhead in constant time;
//
// - `_LIBCPP_HARDENING_MODE_EXTENSIVE` -- sets the hardening mode to "extensive". The extensive mode is a superset of
// the fast mode that additionally enables checks that are relatively cheap and prevent common types of logic errors
// but are not necessarily security-critical;
//
// - `_LIBCPP_HARDENING_MODE_DEBUG` -- sets the hardening mode to "debug". The debug mode is a superset of the extensive
// mode and enables all checks available in the library, including internal assertions. Checks that are part of the
// debug mode can be very expensive and thus the debug mode is intended to be used for testing, not in production.
// Inside the library, assertions are categorized so they can be cherry-picked based on the chosen hardening mode. These
// macros are only for internal use -- users should only pick one of the high-level hardening modes described above.
//
// - `_LIBCPP_ASSERT_VALID_INPUT_RANGE` -- checks that ranges (whether expressed as an iterator pair, an iterator and
// a sentinel, an iterator and a count, or a `std::range`) given as input to library functions are valid:
// - the sentinel is reachable from the begin iterator;
// - TODO(hardening): both iterators refer to the same container.
//
// - `_LIBCPP_ASSERT_VALID_ELEMENT_ACCESS` -- checks that any attempts to access a container element, whether through
// the container object or through an iterator, are valid and do not attempt to go out of bounds or otherwise access
// a non-existent element. For iterator checks to work, bounded iterators must be enabled in the ABI. Types like
// `optional` and `function` are considered one-element containers for the purposes of this check.
//
// - `_LIBCPP_ASSERT_NON_NULL` -- checks that the pointer being dereferenced is not null. On most modern platforms zero
// address does not refer to an actual location in memory, so a null pointer dereference would not compromize the
// memory security of a program (however, it is still undefined behavior that can result in strange errors due to
// compiler optimizations).
//
// - `_LIBCPP_ASSERT_NON_OVERLAPPING_RANGES` -- for functions that take several ranges as arguments, checks that the
// given ranges do not overlap.
//
// - `_LIBCPP_ASSERT_VALID_DEALLOCATION` -- checks that an attempt to deallocate memory is valid (e.g. the given object
// was allocated by the given allocator). Violating this category typically results in a memory leak.
//
// - `_LIBCPP_ASSERT_VALID_EXTERNAL_API_CALL` -- checks that a call to an external API doesn't fail in
// an unexpected manner. This includes triggering documented cases of undefined behavior in an external library (like
// attempting to unlock an unlocked mutex in pthreads). Any API external to the library falls under this category
// (from system calls to compiler intrinsics). We generally don't expect these failures to compromize memory safety or
// otherwise create an immediate security issue.
//
// - `_LIBCPP_ASSERT_COMPATIBLE_ALLOCATOR` -- checks any operations that exchange nodes between containers to make sure
// the containers have compatible allocators.
//
// - `_LIBCPP_ASSERT_ARGUMENT_WITHIN_DOMAIN` -- checks that the given argument is within the domain of valid arguments
// for the function. Violating this typically produces an incorrect result (e.g. the clamp algorithm returns the
// original value without clamping it due to incorrect functors) or puts an object into an invalid state (e.g.
// a string view where only a subset of elements is possible to access). This category is for assertions violating
// which doesn't cause any immediate issues in the library -- whatever the consequences are, they will happen in the
// user code.
//
// - `_LIBCPP_ASSERT_PEDANTIC` -- checks prerequisites which are imposed by the Standard, but violating which happens to
// be benign in our implementation.
//
// - `_LIBCPP_ASSERT_SEMANTIC_REQUIREMENT` -- checks that the given argument satisfies the semantic requirements imposed
// by the Standard. Typically, there is no simple way to completely prove that a semantic requirement is satisfied;
// thus, this would often be a heuristic check and it might be quite expensive.
//
// - `_LIBCPP_ASSERT_INTERNAL` -- checks that internal invariants of the library hold. These assertions don't depend on
// user input.
//
// - `_LIBCPP_ASSERT_UNCATEGORIZED` -- for assertions that haven't been properly classified yet.
// clang-format off
// clang-format on
// The library provides the macro `_LIBCPP_ASSERTION_SEMANTIC` for configuring the assertion semantic used by hardening;
// it can be set to one of the following values:
//
// - `_LIBCPP_ASSERTION_SEMANTIC_IGNORE`;
// - `_LIBCPP_ASSERTION_SEMANTIC_OBSERVE`;
// - `_LIBCPP_ASSERTION_SEMANTIC_QUICK_ENFORCE`;
// - `_LIBCPP_ASSERTION_SEMANTIC_ENFORCE`.
//
// libc++ assertion semantics generally mirror the evaluation semantics of C++26 Contracts:
// - `ignore` evaluates the assertion but doesn't do anything if it fails (note that it differs from the Contracts
// `ignore` semantic which wouldn't evaluate the assertion at all);
// - `observe` logs an error (indicating, if possible, that the error is fatal) and continues execution;
// - `quick-enforce` terminates the program as fast as possible (via trapping);
// - `enforce` logs an error and then terminates the program.
//
// Additionally, a special `hardening-dependent` value selects the assertion semantic based on the hardening mode in
// effect: the production-capable modes (`fast` and `extensive`) map to `quick_enforce` and the `debug` mode maps to
// `enforce`. The `hardening-dependent` semantic cannot be selected explicitly, it is only used when no assertion
// semantic is provided by the user _and_ the library's default semantic is configured to be dependent on hardening.
//
// Notes:
// - Continuing execution after a hardening check fails results in undefined behavior; the `observe` semantic is meant
// to make adopting hardening easier but should not be used outside of this scenario;
// - C++26 wording for Library Hardening precludes a conforming Hardened implementation from using the Contracts
// `ignore` semantic when evaluating hardened preconditions in the Library. Libc++ allows using this semantic for
// hardened preconditions, however, be aware that using `ignore` does not produce a conforming "Hardened"
// implementation, unlike the other semantics above.
// clang-format off
// clang-format on
// If the user attempts to configure the assertion semantic, check that it is allowed in the current environment.
// defined(_LIBCPP_ASSERTION_SEMANTIC)
// User-provided semantic takes top priority -- don't override if set.
// _LIBCPP_ASSERTION_SEMANTIC_DEFAULT != _LIBCPP_ASSERTION_SEMANTIC_HARDENING_DEPENDENT
// #ifndef _LIBCPP_ASSERTION_SEMANTIC
// Finally, validate the selected semantic (in case the user tries setting it to an incorrect value):
// _LIBCPP___CONFIGURATION_HARDENING_H