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