Konstantin Varlamov | 86070a8 | 2024-06-06 23:35:33 | [diff] [blame] | 1 | .. _hardening: |
Mark de Wever | 30d6806 | 2024-01-21 18:48:33 | [diff] [blame] | 2 | |
Konstantin Varlamov | b85e186 | 2023-09-12 19:01:36 | [diff] [blame] | 3 | =============== |
| 4 | Hardening Modes |
| 5 | =============== |
varconst | d1367ca | 2023-07-12 17:12:51 | [diff] [blame] | 6 | |
| 7 | .. contents:: |
| 8 | :local: |
| 9 | |
Konstantin Varlamov | b85e186 | 2023-09-12 19:01:36 | [diff] [blame] | 10 | .. _using-hardening-modes: |
varconst | d1367ca | 2023-07-12 17:12:51 | [diff] [blame] | 11 | |
Konstantin Varlamov | b85e186 | 2023-09-12 19:01:36 | [diff] [blame] | 12 | Using hardening modes |
| 13 | ===================== |
varconst | d1367ca | 2023-07-12 17:12:51 | [diff] [blame] | 14 | |
Konstantin Varlamov | 64d413e | 2023-11-08 19:10:00 | [diff] [blame] | 15 | libc++ provides several hardening modes, where each mode enables a set of |
| 16 | assertions that prevent undefined behavior caused by violating preconditions of |
| 17 | the standard library. Different hardening modes make different trade-offs |
| 18 | between the amount of checking and runtime performance. The available hardening |
| 19 | modes are: |
Konstantin Varlamov | b85e186 | 2023-09-12 19:01:36 | [diff] [blame] | 20 | |
Christopher Di Bella | 64454da | 2023-12-06 22:23:35 | [diff] [blame] | 21 | - **Unchecked mode/none**, which disables all hardening checks. |
| 22 | - **Fast mode**, which contains a set of security-critical checks that can be |
| 23 | done with relatively little overhead in constant time and are intended to be |
| 24 | used in production. We recommend most projects adopt this. |
| 25 | - **Extensive mode**, which contains all the checks from fast mode and some |
| 26 | additional checks for undefined behavior that incur relatively little overhead |
| 27 | but aren't security-critical. Production builds requiring a broader set of |
| 28 | checks than fast mode should consider enabling extensive mode. The additional |
| 29 | rigour impacts performance more than fast mode: we recommend benchmarking to |
| 30 | determine if that is acceptable for your program. |
| 31 | - **Debug mode**, which enables all the available checks in the library, |
Konstantin Varlamov | 86070a8 | 2024-06-06 23:35:33 | [diff] [blame] | 32 | including heuristic checks that might have significant performance overhead as |
| 33 | well as internal library assertions. This mode should be used in |
| 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. |
Konstantin Varlamov | 64d413e | 2023-11-08 19:10:00 | [diff] [blame] | 37 | |
Christopher Di Bella | 64454da | 2023-12-06 22:23:35 | [diff] [blame] | 38 | .. note:: |
Konstantin Varlamov | b85e186 | 2023-09-12 19:01:36 | [diff] [blame] | 39 | |
Christopher Di Bella | 64454da | 2023-12-06 22:23:35 | [diff] [blame] | 40 | Enabling hardening has no impact on the ABI. |
varconst | d1367ca | 2023-07-12 17:12:51 | [diff] [blame] | 41 | |
Christopher Di Bella | 64454da | 2023-12-06 22:23:35 | [diff] [blame] | 42 | Notes for users |
| 43 | --------------- |
varconst | d1367ca | 2023-07-12 17:12:51 | [diff] [blame] | 44 | |
Christopher Di Bella | 64454da | 2023-12-06 22:23:35 | [diff] [blame] | 45 | As a libc++ user, consult with your vendor to determine the level of hardening |
| 46 | enabled by default. |
varconst | d1367ca | 2023-07-12 17:12:51 | [diff] [blame] | 47 | |
Christopher Di Bella | 64454da | 2023-12-06 22:23:35 | [diff] [blame] | 48 | Users wishing for a different hardening level to their vendor default are able |
| 49 | to control the level by passing **one** of the following options to the compiler: |
Konstantin Varlamov | 64d413e | 2023-11-08 19:10:00 | [diff] [blame] | 50 | |
Christopher Di Bella | 64454da | 2023-12-06 22:23:35 | [diff] [blame] | 51 | - ``-D_LIBCPP_HARDENING_MODE=_LIBCPP_HARDENING_MODE_NONE`` |
| 52 | - ``-D_LIBCPP_HARDENING_MODE=_LIBCPP_HARDENING_MODE_FAST`` |
| 53 | - ``-D_LIBCPP_HARDENING_MODE=_LIBCPP_HARDENING_MODE_EXTENSIVE`` |
| 54 | - ``-D_LIBCPP_HARDENING_MODE=_LIBCPP_HARDENING_MODE_DEBUG`` |
Konstantin Varlamov | 64d413e | 2023-11-08 19:10:00 | [diff] [blame] | 55 | |
Christopher Di Bella | 64454da | 2023-12-06 22:23:35 | [diff] [blame] | 56 | .. warning:: |
Konstantin Varlamov | 64d413e | 2023-11-08 19:10:00 | [diff] [blame] | 57 | |
Christopher Di Bella | 64454da | 2023-12-06 22:23:35 | [diff] [blame] | 58 | The exact numeric values of these macros are unspecified and users should not |
| 59 | rely on them (e.g. expect the values to be sorted in any way). |
varconst | f0dfe68 | 2023-07-14 23:58:15 | [diff] [blame] | 60 | |
Christopher Di Bella | 64454da | 2023-12-06 22:23:35 | [diff] [blame] | 61 | .. warning:: |
| 62 | |
| 63 | If you would prefer to override the hardening level on a per-translation-unit |
| 64 | basis, you must do so **before** including any headers to avoid `ODR issues`_. |
| 65 | |
| 66 | .. _`ODR issues`: https://en.cppreference.com/w/cpp/language/definition#:~:text=is%20ill%2Dformed.-,One%20Definition%20Rule,-Only%20one%20definition |
| 67 | |
| 68 | .. note:: |
| 69 | |
| 70 | Since the static and shared library components of libc++ are built by the |
| 71 | vendor, setting this macro will have no impact on the hardening mode for the |
| 72 | pre-built components. Most libc++ code is header-based, so a user-provided |
| 73 | value for ``_LIBCPP_HARDENING_MODE`` will be mostly respected. |
| 74 | |
| 75 | Notes for vendors |
| 76 | ----------------- |
| 77 | |
Konstantin Varlamov | 86070a8 | 2024-06-06 23:35:33 | [diff] [blame] | 78 | Vendors can set the default hardening mode by providing |
| 79 | ``LIBCXX_HARDENING_MODE`` as a configuration option, with the possible values of |
| 80 | ``none``, ``fast``, ``extensive`` and ``debug``. The default value is ``none`` |
| 81 | which doesn't enable any hardening checks (this mode is sometimes called the |
| 82 | ``unchecked`` mode). |
Christopher Di Bella | 64454da | 2023-12-06 22:23:35 | [diff] [blame] | 83 | |
| 84 | This option controls both the hardening mode that the precompiled library is |
| 85 | built with and the default hardening mode that users will build with. If set to |
| 86 | ``none``, the precompiled library will not contain any assertions, and user code |
| 87 | will default to building without assertions. |
varconst | d1367ca | 2023-07-12 17:12:51 | [diff] [blame] | 88 | |
Konstantin Varlamov | 86070a8 | 2024-06-06 23:35:33 | [diff] [blame] | 89 | Vendors can also override the way the program is terminated when an assertion |
| 90 | fails by :ref:`providing a custom header <override-assertion-handler>`. |
Christopher Di Bella | 64454da | 2023-12-06 22:23:35 | [diff] [blame] | 91 | |
Konstantin Varlamov | 86070a8 | 2024-06-06 23:35:33 | [diff] [blame] | 92 | Assertion categories |
| 93 | ==================== |
| 94 | |
| 95 | Inside the library, individual assertions are grouped into different |
| 96 | *categories*. Each hardening mode enables a different set of assertion |
| 97 | categories; categories provide an additional layer of abstraction that makes it |
| 98 | easier to reason about the high-level semantics of a hardening mode. |
| 99 | |
| 100 | .. note:: |
| 101 | |
| 102 | Users are not intended to interact with these categories directly -- the |
| 103 | categories are considered internal to the library and subject to change. |
| 104 | |
| 105 | - ``valid-element-access`` -- checks that any attempts to access a container |
| 106 | element, whether through the container object or through an iterator, are |
| 107 | valid and do not attempt to go out of bounds or otherwise access |
| 108 | a non-existent element. This also includes operations that set up an imminent |
| 109 | invalid access (e.g. incrementing an end iterator). For iterator checks to |
| 110 | work, bounded iterators must be enabled in the ABI. Types like |
| 111 | ``std::optional`` and ``std::function`` are considered containers (with at |
| 112 | most one element) for the purposes of this check. |
| 113 | |
| 114 | - ``valid-input-range`` -- checks that ranges (whether expressed as an iterator |
| 115 | pair, an iterator and a sentinel, an iterator and a count, or |
| 116 | a ``std::range``) given as input to library functions are valid: |
| 117 | - the sentinel is reachable from the begin iterator; |
| 118 | - TODO(hardening): both iterators refer to the same container. |
| 119 | |
| 120 | ("input" here refers to "an input given to an algorithm", not to an iterator |
| 121 | category) |
| 122 | |
| 123 | Violating assertions in this category leads to an out-of-bounds access. |
| 124 | |
| 125 | - ``non-null`` -- checks that the pointer being dereferenced is not null. On |
| 126 | most modern platforms, the zero address does not refer to an actual location |
| 127 | in memory, so a null pointer dereference would not compromise the memory |
| 128 | security of a program (however, it is still undefined behavior that can result |
| 129 | in strange errors due to compiler optimizations). |
| 130 | |
| 131 | - ``non-overlapping-ranges`` -- for functions that take several ranges as |
| 132 | arguments, checks that those ranges do not overlap. |
| 133 | |
| 134 | - ``valid-deallocation`` -- checks that an attempt to deallocate memory is valid |
| 135 | (e.g. the given object was allocated by the given allocator). Violating this |
| 136 | category typically results in a memory leak. |
| 137 | |
| 138 | - ``valid-external-api-call`` -- checks that a call to an external API doesn't |
| 139 | fail in an unexpected manner. This includes triggering documented cases of |
| 140 | undefined behavior in an external library (like attempting to unlock an |
| 141 | unlocked mutex in pthreads). Any API external to the library falls under this |
| 142 | category (from system calls to compiler intrinsics). We generally don't expect |
| 143 | these failures to compromise memory safety or otherwise create an immediate |
| 144 | security issue. |
| 145 | |
| 146 | - ``compatible-allocator`` -- checks any operations that exchange nodes between |
| 147 | containers to make sure the containers have compatible allocators. |
| 148 | |
| 149 | - ``argument-within-domain`` -- checks that the given argument is within the |
| 150 | domain of valid arguments for the function. Violating this typically produces |
| 151 | an incorrect result (e.g. ``std::clamp`` returns the original value without |
| 152 | clamping it due to incorrect functors) or puts an object into an invalid state |
| 153 | (e.g. a string view where only a subset of elements is accessible). This |
| 154 | category is for assertions violating which doesn't cause any immediate issues |
| 155 | in the library -- whatever the consequences are, they will happen in the user |
| 156 | code. |
| 157 | |
| 158 | - ``pedantic`` -- checks preconditions that are imposed by the Standard, but |
| 159 | violating which happens to be benign in libc++. |
| 160 | |
| 161 | - ``semantic-requirement`` -- checks that the given argument satisfies the |
| 162 | semantic requirements imposed by the Standard. Typically, there is no simple |
| 163 | way to completely prove that a semantic requirement is satisfied; thus, this |
| 164 | would often be a heuristic check and it might be quite expensive. |
| 165 | |
| 166 | - ``internal`` -- checks that internal invariants of the library hold. These |
| 167 | assertions don't depend on user input. |
| 168 | |
| 169 | - ``uncategorized`` -- for assertions that haven't been properly classified yet. |
| 170 | This category is an escape hatch used for some existing assertions in the |
| 171 | library; all new code should have its assertions properly classified. |
| 172 | |
| 173 | Mapping between the hardening modes and the assertion categories |
| 174 | ================================================================ |
| 175 | |
| 176 | .. list-table:: |
| 177 | :header-rows: 1 |
| 178 | :widths: auto |
| 179 | |
| 180 | * - Category name |
| 181 | - ``fast`` |
| 182 | - ``extensive`` |
| 183 | - ``debug`` |
| 184 | * - ``valid-element-access`` |
| 185 | - ✅ |
| 186 | - ✅ |
| 187 | - ✅ |
| 188 | * - ``valid-input-range`` |
| 189 | - ✅ |
| 190 | - ✅ |
| 191 | - ✅ |
| 192 | * - ``non-null`` |
| 193 | - ❌ |
| 194 | - ✅ |
| 195 | - ✅ |
| 196 | * - ``non-overlapping-ranges`` |
| 197 | - ❌ |
| 198 | - ✅ |
| 199 | - ✅ |
| 200 | * - ``valid-deallocation`` |
| 201 | - ❌ |
| 202 | - ✅ |
| 203 | - ✅ |
| 204 | * - ``valid-external-api-call`` |
| 205 | - ❌ |
| 206 | - ✅ |
| 207 | - ✅ |
| 208 | * - ``compatible-allocator`` |
| 209 | - ❌ |
| 210 | - ✅ |
| 211 | - ✅ |
| 212 | * - ``argument-within-domain`` |
| 213 | - ❌ |
| 214 | - ✅ |
| 215 | - ✅ |
| 216 | * - ``pedantic`` |
| 217 | - ❌ |
| 218 | - ✅ |
| 219 | - ✅ |
| 220 | * - ``semantic-requirement`` |
| 221 | - ❌ |
| 222 | - ❌ |
| 223 | - ✅ |
| 224 | * - ``internal`` |
| 225 | - ❌ |
| 226 | - ❌ |
| 227 | - ✅ |
| 228 | * - ``uncategorized`` |
| 229 | - ❌ |
| 230 | - ✅ |
| 231 | - ✅ |
| 232 | |
| 233 | .. note:: |
| 234 | |
| 235 | At the moment, each subsequent hardening mode is a strict superset of the |
| 236 | previous one (in other words, each subsequent mode only enables additional |
| 237 | assertion categories without disabling any), but this won't necessarily be |
| 238 | true for any hardening modes that might be added in the future. |
| 239 | |
| 240 | .. note:: |
| 241 | |
| 242 | The categories enabled by each mode are subject to change and users should not |
| 243 | rely on the precise assertions enabled by a mode at a given point in time. |
| 244 | However, the library does guarantee to keep the hardening modes stable and |
| 245 | to fulfill the semantics documented here. |
| 246 | |
| 247 | Hardening assertion failure |
| 248 | =========================== |
| 249 | |
| 250 | In production modes (``fast`` and ``extensive``), a hardening assertion failure |
Louis Dionne | dbfb29f | 2025-02-12 22:57:37 | [diff] [blame] | 251 | immediately ``_traps <https://clang.llvm.org/docs/LanguageExtensions.html#builtin-verbose-trap>`` |
Konstantin Varlamov | 86070a8 | 2024-06-06 23:35:33 | [diff] [blame] | 252 | the program. This is the safest approach that also minimizes the code size |
| 253 | penalty as the failure handler maps to a single instruction. The downside is |
| 254 | that the failure provides no additional details other than the stack trace |
| 255 | (which might also be affected by optimizations). |
| 256 | |
Konstantin Varlamov | 86070a8 | 2024-06-06 23:35:33 | [diff] [blame] | 257 | In the ``debug`` mode, an assertion failure terminates the program in an |
| 258 | unspecified manner and also outputs the associated error message to the error |
| 259 | output. This is less secure and increases the size of the binary (among other |
| 260 | things, it has to store the error message strings) but makes the failure easier |
| 261 | to debug. It also allows testing the error messages in our test suite. |
| 262 | |
| 263 | .. _override-assertion-handler: |
| 264 | |
| 265 | Overriding the assertion failure handler |
| 266 | ---------------------------------------- |
| 267 | |
| 268 | Vendors can override the default assertion handler mechanism by following these |
| 269 | steps: |
| 270 | |
| 271 | - create a header file that provides a definition of a macro called |
| 272 | ``_LIBCPP_ASSERTION_HANDLER``. The macro will be invoked when a hardening |
| 273 | assertion fails, with a single parameter containing a null-terminated string |
| 274 | with the error message. |
| 275 | - when configuring the library, provide the path to custom header (relative to |
| 276 | the root of the repository) via the CMake variable |
| 277 | ``LIBCXX_ASSERTION_HANDLER_FILE``. |
| 278 | |
| 279 | Note that almost all libc++ headers include the assertion handler header which |
| 280 | means it should not include anything non-trivial from the standard library to |
| 281 | avoid creating circular dependencies. |
| 282 | |
| 283 | There is no existing mechanism for users to override the assertion handler |
| 284 | because the ability to do the override other than at configure-time carries an |
| 285 | unavoidable code size penalty that would otherwise be imposed on all users, |
| 286 | whether they require such customization or not. Instead, we let vendors decide |
| 287 | what's right on their platform for their users -- a vendor who wishes to provide |
| 288 | this capability is free to do so, e.g. by declaring the assertion handler as an |
| 289 | overridable function. |
| 290 | |
| 291 | ABI |
| 292 | === |
| 293 | |
| 294 | Setting a hardening mode does **not** affect the ABI. Each mode uses the subset |
| 295 | of checks available in the current ABI configuration which is determined by the |
| 296 | platform. |
| 297 | |
| 298 | It is important to stress that whether a particular check is enabled depends on |
| 299 | the combination of the selected hardening mode and the hardening-related ABI |
| 300 | options. Some checks require changing the ABI from the "default" to store |
| 301 | additional information in the library classes -- e.g. checking whether an |
| 302 | iterator is valid upon dereference generally requires storing data about bounds |
| 303 | inside the iterator object. Using ``std::span`` as an example, setting the |
| 304 | hardening mode to ``fast`` will always enable the ``valid-element-access`` |
| 305 | checks when accessing elements via a ``std::span`` object, but whether |
| 306 | dereferencing a ``std::span`` iterator does the equivalent check depends on the |
| 307 | ABI configuration. |
| 308 | |
| 309 | ABI options |
| 310 | ----------- |
| 311 | |
Louis Dionne | 1855333 | 2025-01-07 21:47:39 | [diff] [blame] | 312 | Vendors can use some ABI options at CMake configuration time (when building libc++ |
| 313 | itself) to enable additional hardening checks. This is done by passing these |
| 314 | macros as ``-DLIBCXX_ABI_DEFINES="_LIBCPP_ABI_FOO;_LIBCPP_ABI_BAR;etc"`` at |
| 315 | CMake configuration time. The available options are: |
Konstantin Varlamov | 86070a8 | 2024-06-06 23:35:33 | [diff] [blame] | 316 | |
| 317 | - ``_LIBCPP_ABI_BOUNDED_ITERATORS`` -- changes the iterator type of select |
| 318 | containers (see below) to a bounded iterator that keeps track of whether it's |
| 319 | within the bounds of the original container and asserts valid bounds on every |
| 320 | dereference. |
| 321 | |
| 322 | ABI impact: changes the iterator type of the relevant containers. |
| 323 | |
| 324 | Supported containers: |
| 325 | |
| 326 | - ``span``; |
| 327 | - ``string_view``. |
| 328 | |
David Benjamin | bcf9fb9 | 2024-07-23 05:44:25 | [diff] [blame] | 329 | - ``_LIBCPP_ABI_BOUNDED_ITERATORS_IN_STRING`` -- changes the iterator type of |
| 330 | ``basic_string`` to a bounded iterator that keeps track of whether it's within |
| 331 | the bounds of the original container and asserts it on every dereference and |
| 332 | when performing iterator arithmetics. |
| 333 | |
| 334 | ABI impact: changes the iterator type of ``basic_string`` and its |
| 335 | specializations, such as ``string`` and ``wstring``. |
| 336 | |
| 337 | - ``_LIBCPP_ABI_BOUNDED_ITERATORS_IN_VECTOR`` -- changes the iterator type of |
| 338 | ``vector`` to a bounded iterator that keeps track of whether it's within the |
| 339 | bounds of the original container and asserts it on every dereference and when |
| 340 | performing iterator arithmetics. Note: this doesn't yet affect |
| 341 | ``vector<bool>``. |
| 342 | |
| 343 | ABI impact: changes the iterator type of ``vector`` (except ``vector<bool>``). |
| 344 | |
Louis Dionne | 9612175 | 2025-01-07 21:47:06 | [diff] [blame] | 345 | - ``_LIBCPP_ABI_BOUNDED_UNIQUE_PTR`` -- tracks the bounds of the array stored inside |
Louis Dionne | dfe737f | 2024-11-04 15:45:12 | [diff] [blame] | 346 | a ``std::unique_ptr<T[]>``, allowing it to trap when accessed out-of-bounds. This |
| 347 | requires the ``std::unique_ptr`` to be created using an API like ``std::make_unique`` |
| 348 | or ``std::make_unique_for_overwrite``, otherwise the bounds information is not available |
| 349 | to the library. |
| 350 | |
| 351 | ABI impact: changes the layout of ``std::unique_ptr<T[]>``, and the representation |
| 352 | of a few library types that use ``std::unique_ptr`` internally, such as |
| 353 | the unordered containers. |
| 354 | |
Louis Dionne | 427a5cf | 2024-11-07 14:23:21 | [diff] [blame] | 355 | - ``_LIBCPP_ABI_BOUNDED_ITERATORS_IN_STD_ARRAY`` -- changes the iterator type of ``std::array`` to a |
| 356 | bounded iterator that keeps track of whether it's within the bounds of the container and asserts it |
| 357 | on every dereference and when performing iterator arithmetic. |
| 358 | |
| 359 | ABI impact: changes the iterator type of ``std::array``, its size and its layout. |
| 360 | |
Konstantin Varlamov | 86070a8 | 2024-06-06 23:35:33 | [diff] [blame] | 361 | ABI tags |
| 362 | -------- |
| 363 | |
| 364 | We use ABI tags to allow translation units built with different hardening modes |
| 365 | to interact with each other without causing ODR violations. Knowing how |
| 366 | hardening modes are encoded into the ABI tags might be useful to examine |
| 367 | a binary and determine whether it was built with hardening enabled. |
| 368 | |
| 369 | .. warning:: |
| 370 | We don't commit to the encoding scheme used by the ABI tags being stable |
| 371 | between different releases of libc++. The tags themselves are never stable, by |
| 372 | design -- new releases increase the version number. The following describes |
| 373 | the state of the latest release and is for informational purposes only. |
| 374 | |
| 375 | The first character of an ABI tag encodes the hardening mode: |
| 376 | |
| 377 | - ``f`` -- [f]ast mode; |
| 378 | - ``s`` -- extensive ("[s]afe") mode; |
| 379 | - ``d`` -- [d]ebug mode; |
| 380 | - ``n`` -- [n]one mode. |
| 381 | |
| 382 | Hardened containers status |
| 383 | ========================== |
| 384 | |
| 385 | .. list-table:: |
| 386 | :header-rows: 1 |
| 387 | :widths: auto |
| 388 | |
| 389 | * - Name |
| 390 | - Member functions |
| 391 | - Iterators (ABI-dependent) |
| 392 | * - ``span`` |
| 393 | - ✅ |
| 394 | - ✅ |
| 395 | * - ``string_view`` |
| 396 | - ✅ |
| 397 | - ✅ |
| 398 | * - ``array`` |
| 399 | - ✅ |
| 400 | - ❌ |
| 401 | * - ``vector`` |
| 402 | - ✅ |
David Benjamin | bcf9fb9 | 2024-07-23 05:44:25 | [diff] [blame] | 403 | - ✅ (see note) |
Konstantin Varlamov | 86070a8 | 2024-06-06 23:35:33 | [diff] [blame] | 404 | * - ``string`` |
| 405 | - ✅ |
David Benjamin | bcf9fb9 | 2024-07-23 05:44:25 | [diff] [blame] | 406 | - ✅ (see note) |
Konstantin Varlamov | 86070a8 | 2024-06-06 23:35:33 | [diff] [blame] | 407 | * - ``list`` |
| 408 | - ✅ |
| 409 | - ❌ |
| 410 | * - ``forward_list`` |
Konstantin Varlamov | bda7c9a | 2025-01-06 20:50:00 | [diff] [blame] | 411 | - ✅ |
Konstantin Varlamov | 86070a8 | 2024-06-06 23:35:33 | [diff] [blame] | 412 | - ❌ |
| 413 | * - ``deque`` |
| 414 | - ✅ |
| 415 | - ❌ |
| 416 | * - ``map`` |
| 417 | - ❌ |
| 418 | - ❌ |
| 419 | * - ``set`` |
| 420 | - ❌ |
| 421 | - ❌ |
| 422 | * - ``multimap`` |
| 423 | - ❌ |
| 424 | - ❌ |
| 425 | * - ``multiset`` |
| 426 | - ❌ |
| 427 | - ❌ |
| 428 | * - ``unordered_map`` |
| 429 | - Partial |
| 430 | - Partial |
| 431 | * - ``unordered_set`` |
| 432 | - Partial |
| 433 | - Partial |
| 434 | * - ``unordered_multimap`` |
| 435 | - Partial |
| 436 | - Partial |
| 437 | * - ``unordered_multiset`` |
| 438 | - Partial |
| 439 | - Partial |
| 440 | * - ``mdspan`` |
| 441 | - ✅ |
| 442 | - ❌ |
| 443 | * - ``optional`` |
| 444 | - ✅ |
| 445 | - N/A |
| 446 | * - ``function`` |
| 447 | - ❌ |
| 448 | - N/A |
| 449 | * - ``variant`` |
| 450 | - N/A |
| 451 | - N/A |
| 452 | * - ``any`` |
| 453 | - N/A |
| 454 | - N/A |
| 455 | * - ``expected`` |
| 456 | - ✅ |
| 457 | - N/A |
| 458 | * - ``valarray`` |
| 459 | - Partial |
| 460 | - N/A |
| 461 | * - ``bitset`` |
Konstantin Varlamov | ac1d560 | 2024-12-25 02:22:18 | [diff] [blame] | 462 | - ✅ |
Konstantin Varlamov | 86070a8 | 2024-06-06 23:35:33 | [diff] [blame] | 463 | - N/A |
| 464 | |
David Benjamin | bcf9fb9 | 2024-07-23 05:44:25 | [diff] [blame] | 465 | Note: for ``vector`` and ``string``, the iterator does not check for |
| 466 | invalidation (accesses made via an invalidated iterator still lead to undefined |
| 467 | behavior) |
| 468 | |
| 469 | Note: ``vector<bool>`` iterator is not currently hardened. |
| 470 | |
Konstantin Varlamov | 86070a8 | 2024-06-06 23:35:33 | [diff] [blame] | 471 | Testing |
| 472 | ======= |
| 473 | |
| 474 | Please see :ref:`Testing documentation <testing-hardening-assertions>`. |
| 475 | |
| 476 | Further reading |
| 477 | =============== |
| 478 | |
David Spickett | 1e6d5de | 2024-07-01 07:06:30 | [diff] [blame] | 479 | - `Hardening RFC <https://discourse.llvm.org/t/rfc-hardening-in-libc/73925>`_: |
Konstantin Varlamov | 86070a8 | 2024-06-06 23:35:33 | [diff] [blame] | 480 | contains some of the design rationale. |