@@ -31,9 +31,9 @@ modes are:
31
31
- **Debug mode **, which enables all the available checks in the library,
32
32
including heuristic checks that might have significant performance overhead as
33
33
well as internal library assertions. This mode should be used in
34
- non-production environments (such as test suites, CI, local development). We
35
- don’t commit to a particular level of performance in this mode and it’s * not *
36
- intended to be used in production.
34
+ non-production environments (such as test suites, CI, or local development).
35
+ We don’t commit to a particular level of performance in this mode and it’s
36
+ * not * intended to be used in production.
37
37
38
38
.. note ::
39
39
@@ -101,8 +101,8 @@ easier to reason about the high-level semantics of a hardening mode.
101
101
element, whether through the container object or through an iterator, are
102
102
valid and do not attempt to go out of bounds or otherwise access
103
103
a non-existent element. For iterator checks to work, bounded iterators must be
104
- enabled in the ABI. Types like ``optional `` and ``function `` are considered
105
- one-element containers for the purposes of this check.
104
+ enabled in the ABI. Types like ``std:: optional `` and ``std:: function `` are
105
+ considered one-element containers for the purposes of this check.
106
106
107
107
- ``valid-input-range `` -- checks that ranges (whether expressed as an iterator
108
108
pair, an iterator and a sentinel, an iterator and a count, or
@@ -116,13 +116,13 @@ easier to reason about the high-level semantics of a hardening mode.
116
116
Violating assertions in this category leads to an out-of-bounds access.
117
117
118
118
- ``non-null `` -- checks that the pointer being dereferenced is not null. On
119
- most modern platforms zero address does not refer to an actual location in
120
- memory, so a null pointer dereference would not compromize the memory security
121
- of a program (however, it is still undefined behavior that can result in
122
- strange errors due to compiler optimizations).
119
+ most modern platforms, the zero address does not refer to an actual location
120
+ in memory, so a null pointer dereference would not compromise the memory
121
+ security of a program (however, it is still undefined behavior that can result
122
+ in strange errors due to compiler optimizations).
123
123
124
124
- ``non-overlapping-ranges `` -- for functions that take several ranges as
125
- arguments, checks that the given ranges do not overlap.
125
+ arguments, checks that those ranges do not overlap.
126
126
127
127
- ``valid-deallocation `` -- checks that an attempt to deallocate memory is valid
128
128
(e.g. the given object was allocated by the given allocator). Violating this
@@ -133,22 +133,22 @@ easier to reason about the high-level semantics of a hardening mode.
133
133
undefined behavior in an external library (like attempting to unlock an
134
134
unlocked mutex in pthreads). Any API external to the library falls under this
135
135
category (from system calls to compiler intrinsics). We generally don't expect
136
- these failures to compromize memory safety or otherwise create an immediate
136
+ these failures to compromise memory safety or otherwise create an immediate
137
137
security issue.
138
138
139
139
- ``compatible-allocator `` -- checks any operations that exchange nodes between
140
140
containers to make sure the containers have compatible allocators.
141
141
142
142
- ``argument-within-domain `` -- checks that the given argument is within the
143
143
domain of valid arguments for the function. Violating this typically produces
144
- an incorrect result (e.g. the clamp algorithm returns the original value
145
- without clamping it due to incorrect functors) or puts an object into an
146
- invalid state (e.g. a string view where only a subset of elements is possible
147
- to access). This category is for assertions violating which doesn't cause any
148
- immediate issues in the library -- whatever the consequences are, they will
149
- happen in the user code.
150
-
151
- - ``pedantic `` -- checks prerequisites that are imposed by the Standard, but
144
+ an incorrect result (e.g. `` std:: clamp`` returns the original value without
145
+ clamping it due to incorrect functors) or puts an object into an invalid state
146
+ (e.g. a string view where only a subset of elements is accessible). This
147
+ category is for assertions violating which doesn't cause any immediate issues
148
+ in the library -- whatever the consequences are, they will happen in the user
149
+ code.
150
+
151
+ - ``pedantic `` -- checks preconditions that are imposed by the Standard, but
152
152
violating which happens to be benign in our implementation.
153
153
154
154
- ``semantic-requirement `` -- checks that the given argument satisfies the
@@ -160,8 +160,8 @@ easier to reason about the high-level semantics of a hardening mode.
160
160
assertions don't depend on user input.
161
161
162
162
- ``uncategorized `` -- for assertions that haven't been properly classified yet.
163
- This is an escape hatch used for some existing assertions in the library; all
164
- new code should have its assertions properly classified.
163
+ This category is an escape hatch used for some existing assertions in the
164
+ library; all new code should have its assertions properly classified.
165
165
166
166
Mapping between the hardening modes and the assertion categories
167
167
================================================================
@@ -228,24 +228,25 @@ Mapping between the hardening modes and the assertion categories
228
228
At the moment, each subsequent hardening mode is a strict superset of the
229
229
previous one (in other words, each subsequent mode only enables additional
230
230
assertion categories without disabling any), but this won't necessarily be
231
- true for any hardening modes that might potentially be added in the future.
231
+ true for any hardening modes that might be added in the future.
232
232
233
233
Hardening assertion failure
234
234
===========================
235
235
236
236
In production modes (``fast `` and ``extensive ``), a hardening assertion failure
237
- immediately traps the program. This is the safest approach that also minimizes
238
- the code size penalty as the failure handler maps to a single instruction. The
239
- downside is that the failure provides no additional details other than the stack
240
- trace (which might also be affected by optimizations).
237
+ immediately ``_traps <https://llvm.org/docs/LangRef.html#llvm-trap-intrinsic> ``
238
+ the program. This is the safest approach that also minimizes the code size
239
+ penalty as the failure handler maps to a single instruction. The downside is
240
+ that the failure provides no additional details other than the stack trace
241
+ (which might also be affected by optimizations).
241
242
242
243
TODO(hardening): describe ``__builtin_verbose_trap `` once we can use it.
243
244
244
245
In the ``debug `` mode, an assertion failure terminates the program in an
245
246
unspecified manner and also outputs the associated error message to the error
246
247
output. This is less secure and increases the size of the binary (among other
247
- things, to store the error message strings) but makes the failure easier to
248
- debug. It also allows us to test the error messages in our test suite.
248
+ things, it has to store the error message strings) but makes the failure easier
249
+ to debug. It also allows us to test the error messages in our test suite.
249
250
250
251
.. _override-assertion-handler :
251
252
@@ -277,8 +278,9 @@ additional information in the library classes -- e.g. checking whether an
277
278
iterator is valid upon dereference generally requires storing data about bounds
278
279
inside the iterator object. Using ``std::span `` as an example, setting the
279
280
hardening mode to ``fast `` will always enable the ``valid-element-access ``
280
- checks when accessing elements via a ``span `` object, but whether dereferencing
281
- a ``span `` iterator does the equivalent check depends on the ABI configuration.
281
+ checks when accessing elements via a ``std::span `` object, but whether
282
+ dereferencing a ``std::span `` iterator does the equivalent check depends on the
283
+ ABI configuration.
282
284
283
285
ABI options
284
286
-----------
@@ -287,7 +289,7 @@ Vendors can use the following ABI options to enable additional hardening checks:
287
289
288
290
- ``_LIBCPP_ABI_BOUNDED_ITERATORS `` -- changes the iterator type of select
289
291
containers (see below) to a bounded iterator that keeps track of whether it's
290
- within the bounds of the original container and asserts it on every
292
+ within the bounds of the original container and asserts valid bounds on every
291
293
dereference.
292
294
293
295
ABI impact: changes the iterator type of the relevant containers.
@@ -305,9 +307,10 @@ hardening modes are encoded into the ABI tags might be useful to examine
305
307
a binary and determine whether it was built with hardening enabled.
306
308
307
309
.. warning ::
308
- We don't commit to the ABI tags being stable between different releases of
309
- libc++. The following describes the state of the latest release and is for
310
- informational purposes only.
310
+ We don't commit to the encoding scheme used by the ABI tags being stable
311
+ between different releases of libc++. The tags themselves are never stable, by
312
+ design -- new releases increase the version number. The following describes
313
+ the state of the latest release and is for informational purposes only.
311
314
312
315
The first character of an ABI tag encodes the hardening mode:
313
316
@@ -365,7 +368,39 @@ Testing
365
368
Each hardening assertion should be tested using death tests (via the
366
369
``TEST_LIBCPP_ASSERT_FAILURE `` macro). Use the ``libcpp-hardening-mode `` Lit
367
370
feature to make sure the assertion is enabled in (and only in) the intended
368
- modes. Note that error messages are only tested (matched) if the ``debug ``
371
+ modes. The convention is to use `assert. ` in the name of the test file to make
372
+ it easier to identify as a hardening test, e.g. ``assert.my_func.pass.cpp ``.
373
+ A toy example:
374
+
375
+ .. code-block :: cpp
376
+
377
+ // Note: the following three annotations are currently needed to use the
378
+ // `TEST_LIBCPP_ASSERT_FAILURE`.
379
+ // REQUIRES: has-unix-headers
380
+ // UNSUPPORTED: c++03
381
+ // XFAIL: libcpp-hardening-mode=debug && availability-verbose_abort-missing
382
+
383
+ // Example: only run this test in `fast`/`extensive`/`debug` modes.
384
+ // UNSUPPORTED: libcpp-hardening-mode=none
385
+ // Example: only run this test in the `debug` mode.
386
+ // REQUIRES: libcpp-hardening-mode=debug
387
+ // Example: only run this test in `extensive`/`debug` modes.
388
+ // REQUIRES: libcpp-hardening-mode={{extensive|debug}}
389
+
390
+ #include <header_being_tested>
391
+
392
+ #include "check_assertion.h" // Contains the `TEST_LIBCPP_ASSERT_FAILURE` macro
393
+
394
+ int main(int, char**) {
395
+ std::type_being_tested foo;
396
+ int bad_input = -1;
397
+ TEST_LIBCPP_ASSERT_FAILURE(foo.some_function_that_asserts(bad_input),
398
+ "The expected assertion message");
399
+
400
+ return 0;
401
+ }
402
+
403
+ Note that error messages are only tested (matched) if the ``debug ``
369
404
hardening mode is used.
370
405
371
406
Further reading
0 commit comments