Skip to content

Commit c95f9a7

Browse files
committed
Address feedback
1 parent b2b4688 commit c95f9a7

File tree

1 file changed

+70
-35
lines changed

1 file changed

+70
-35
lines changed

libcxx/docs/Hardening.rst

Lines changed: 70 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,9 @@ modes are:
3131
- **Debug mode**, which enables all the available checks in the library,
3232
including heuristic checks that might have significant performance overhead as
3333
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.
3737

3838
.. note::
3939

@@ -101,8 +101,8 @@ easier to reason about the high-level semantics of a hardening mode.
101101
element, whether through the container object or through an iterator, are
102102
valid and do not attempt to go out of bounds or otherwise access
103103
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.
106106

107107
- ``valid-input-range`` -- checks that ranges (whether expressed as an iterator
108108
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.
116116
Violating assertions in this category leads to an out-of-bounds access.
117117

118118
- ``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).
123123

124124
- ``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.
126126

127127
- ``valid-deallocation`` -- checks that an attempt to deallocate memory is valid
128128
(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.
133133
undefined behavior in an external library (like attempting to unlock an
134134
unlocked mutex in pthreads). Any API external to the library falls under this
135135
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
137137
security issue.
138138

139139
- ``compatible-allocator`` -- checks any operations that exchange nodes between
140140
containers to make sure the containers have compatible allocators.
141141

142142
- ``argument-within-domain`` -- checks that the given argument is within the
143143
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
152152
violating which happens to be benign in our implementation.
153153

154154
- ``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.
160160
assertions don't depend on user input.
161161

162162
- ``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.
165165

166166
Mapping between the hardening modes and the assertion categories
167167
================================================================
@@ -228,24 +228,25 @@ Mapping between the hardening modes and the assertion categories
228228
At the moment, each subsequent hardening mode is a strict superset of the
229229
previous one (in other words, each subsequent mode only enables additional
230230
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.
232232

233233
Hardening assertion failure
234234
===========================
235235

236236
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).
241242

242243
TODO(hardening): describe ``__builtin_verbose_trap`` once we can use it.
243244

244245
In the ``debug`` mode, an assertion failure terminates the program in an
245246
unspecified manner and also outputs the associated error message to the error
246247
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.
249250

250251
.. _override-assertion-handler:
251252

@@ -277,8 +278,9 @@ additional information in the library classes -- e.g. checking whether an
277278
iterator is valid upon dereference generally requires storing data about bounds
278279
inside the iterator object. Using ``std::span`` as an example, setting the
279280
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.
282284

283285
ABI options
284286
-----------
@@ -287,7 +289,7 @@ Vendors can use the following ABI options to enable additional hardening checks:
287289

288290
- ``_LIBCPP_ABI_BOUNDED_ITERATORS`` -- changes the iterator type of select
289291
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
291293
dereference.
292294

293295
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
305307
a binary and determine whether it was built with hardening enabled.
306308

307309
.. 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.
311314

312315
The first character of an ABI tag encodes the hardening mode:
313316

@@ -365,7 +368,39 @@ Testing
365368
Each hardening assertion should be tested using death tests (via the
366369
``TEST_LIBCPP_ASSERT_FAILURE`` macro). Use the ``libcpp-hardening-mode`` Lit
367370
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``
369404
hardening mode is used.
370405

371406
Further reading

0 commit comments

Comments
 (0)