Skip to content

Commit 6d80d09

Browse files
committed
[libc++] Split macros related to hardening into their own header
Hardening macros are easy to extract into their own header, and doing so decreases the complexity of the main __config file.
1 parent baf41d2 commit 6d80d09

File tree

5 files changed

+225
-189
lines changed

5 files changed

+225
-189
lines changed

libcxx/include/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -328,6 +328,8 @@ set(files
328328
__configuration/abi.h
329329
__configuration/availability.h
330330
__configuration/compiler.h
331+
__configuration/experimental.h
332+
__configuration/hardening.h
331333
__configuration/language.h
332334
__configuration/platform.h
333335
__coroutine/coroutine_handle.h

libcxx/include/__config

Lines changed: 2 additions & 189 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414
#include <__configuration/abi.h>
1515
#include <__configuration/availability.h>
1616
#include <__configuration/compiler.h>
17+
#include <__configuration/experimental.h>
18+
#include <__configuration/hardening.h>
1719
#include <__configuration/language.h>
1820
#include <__configuration/platform.h>
1921

@@ -38,195 +40,6 @@
3840
# define _LIBCPP_FREESTANDING
3941
# endif
4042

41-
// NOLINTNEXTLINE(libcpp-cpp-version-check)
42-
# if __cplusplus < 201103L
43-
# define _LIBCPP_CXX03_LANG
44-
# endif
45-
46-
# if __has_feature(experimental_library)
47-
# ifndef _LIBCPP_ENABLE_EXPERIMENTAL
48-
# define _LIBCPP_ENABLE_EXPERIMENTAL
49-
# endif
50-
# endif
51-
52-
// Incomplete features get their own specific disabling flags. This makes it
53-
// easier to grep for target specific flags once the feature is complete.
54-
# if defined(_LIBCPP_ENABLE_EXPERIMENTAL) || defined(_LIBCPP_BUILDING_LIBRARY)
55-
# define _LIBCPP_HAS_EXPERIMENTAL_LIBRARY 1
56-
# else
57-
# define _LIBCPP_HAS_EXPERIMENTAL_LIBRARY 0
58-
# endif
59-
60-
# define _LIBCPP_HAS_EXPERIMENTAL_PSTL _LIBCPP_HAS_EXPERIMENTAL_LIBRARY
61-
# define _LIBCPP_HAS_EXPERIMENTAL_TZDB _LIBCPP_HAS_EXPERIMENTAL_LIBRARY
62-
# define _LIBCPP_HAS_EXPERIMENTAL_SYNCSTREAM _LIBCPP_HAS_EXPERIMENTAL_LIBRARY
63-
# define _LIBCPP_HAS_EXPERIMENTAL_HARDENING_OBSERVE_SEMANTIC _LIBCPP_HAS_EXPERIMENTAL_LIBRARY
64-
65-
// HARDENING {
66-
67-
// TODO(LLVM 23): Remove this. We're making these an error to catch folks who might not have migrated.
68-
// Since hardening went through several changes (many of which impacted user-facing macros),
69-
// we're keeping these checks around for a bit longer than usual. Failure to properly configure
70-
// hardening results in checks being dropped silently, which is a pretty big deal.
71-
# if defined(_LIBCPP_ENABLE_ASSERTIONS)
72-
# error "_LIBCPP_ENABLE_ASSERTIONS has been removed, please use _LIBCPP_HARDENING_MODE=<mode> instead (see docs)"
73-
# endif
74-
# if defined(_LIBCPP_ENABLE_HARDENED_MODE)
75-
# error "_LIBCPP_ENABLE_HARDENED_MODE has been removed, please use _LIBCPP_HARDENING_MODE=<mode> instead (see docs)"
76-
# endif
77-
# if defined(_LIBCPP_ENABLE_SAFE_MODE)
78-
# error "_LIBCPP_ENABLE_SAFE_MODE has been removed, please use _LIBCPP_HARDENING_MODE=<mode> instead (see docs)"
79-
# endif
80-
# if defined(_LIBCPP_ENABLE_DEBUG_MODE)
81-
# error "_LIBCPP_ENABLE_DEBUG_MODE has been removed, please use _LIBCPP_HARDENING_MODE=<mode> instead (see docs)"
82-
# endif
83-
84-
// The library provides the macro `_LIBCPP_HARDENING_MODE` which can be set to one of the following values:
85-
//
86-
// - `_LIBCPP_HARDENING_MODE_NONE`;
87-
// - `_LIBCPP_HARDENING_MODE_FAST`;
88-
// - `_LIBCPP_HARDENING_MODE_EXTENSIVE`;
89-
// - `_LIBCPP_HARDENING_MODE_DEBUG`.
90-
//
91-
// These values have the following effects:
92-
//
93-
// - `_LIBCPP_HARDENING_MODE_NONE` -- sets the hardening mode to "none" which disables all runtime hardening checks;
94-
//
95-
// - `_LIBCPP_HARDENING_MODE_FAST` -- sets that hardening mode to "fast". The fast mode enables security-critical checks
96-
// that can be done with relatively little runtime overhead in constant time;
97-
//
98-
// - `_LIBCPP_HARDENING_MODE_EXTENSIVE` -- sets the hardening mode to "extensive". The extensive mode is a superset of
99-
// the fast mode that additionally enables checks that are relatively cheap and prevent common types of logic errors
100-
// but are not necessarily security-critical;
101-
//
102-
// - `_LIBCPP_HARDENING_MODE_DEBUG` -- sets the hardening mode to "debug". The debug mode is a superset of the extensive
103-
// mode and enables all checks available in the library, including internal assertions. Checks that are part of the
104-
// debug mode can be very expensive and thus the debug mode is intended to be used for testing, not in production.
105-
106-
// Inside the library, assertions are categorized so they can be cherry-picked based on the chosen hardening mode. These
107-
// macros are only for internal use -- users should only pick one of the high-level hardening modes described above.
108-
//
109-
// - `_LIBCPP_ASSERT_VALID_INPUT_RANGE` -- checks that ranges (whether expressed as an iterator pair, an iterator and
110-
// a sentinel, an iterator and a count, or a `std::range`) given as input to library functions are valid:
111-
// - the sentinel is reachable from the begin iterator;
112-
// - TODO(hardening): both iterators refer to the same container.
113-
//
114-
// - `_LIBCPP_ASSERT_VALID_ELEMENT_ACCESS` -- checks that any attempts to access a container element, whether through
115-
// the container object or through an iterator, are valid and do not attempt to go out of bounds or otherwise access
116-
// a non-existent element. For iterator checks to work, bounded iterators must be enabled in the ABI. Types like
117-
// `optional` and `function` are considered one-element containers for the purposes of this check.
118-
//
119-
// - `_LIBCPP_ASSERT_NON_NULL` -- checks that the pointer being dereferenced is not null. On most modern platforms zero
120-
// address does not refer to an actual location in memory, so a null pointer dereference would not compromize the
121-
// memory security of a program (however, it is still undefined behavior that can result in strange errors due to
122-
// compiler optimizations).
123-
//
124-
// - `_LIBCPP_ASSERT_NON_OVERLAPPING_RANGES` -- for functions that take several ranges as arguments, checks that the
125-
// given ranges do not overlap.
126-
//
127-
// - `_LIBCPP_ASSERT_VALID_DEALLOCATION` -- checks that an attempt to deallocate memory is valid (e.g. the given object
128-
// was allocated by the given allocator). Violating this category typically results in a memory leak.
129-
//
130-
// - `_LIBCPP_ASSERT_VALID_EXTERNAL_API_CALL` -- checks that a call to an external API doesn't fail in
131-
// an unexpected manner. This includes triggering documented cases of undefined behavior in an external library (like
132-
// attempting to unlock an unlocked mutex in pthreads). Any API external to the library falls under this category
133-
// (from system calls to compiler intrinsics). We generally don't expect these failures to compromize memory safety or
134-
// otherwise create an immediate security issue.
135-
//
136-
// - `_LIBCPP_ASSERT_COMPATIBLE_ALLOCATOR` -- checks any operations that exchange nodes between containers to make sure
137-
// the containers have compatible allocators.
138-
//
139-
// - `_LIBCPP_ASSERT_ARGUMENT_WITHIN_DOMAIN` -- checks that the given argument is within the domain of valid arguments
140-
// for the function. Violating this typically produces an incorrect result (e.g. the clamp algorithm returns the
141-
// original value without clamping it due to incorrect functors) or puts an object into an invalid state (e.g.
142-
// a string view where only a subset of elements is possible to access). This category is for assertions violating
143-
// which doesn't cause any immediate issues in the library -- whatever the consequences are, they will happen in the
144-
// user code.
145-
//
146-
// - `_LIBCPP_ASSERT_PEDANTIC` -- checks prerequisites which are imposed by the Standard, but violating which happens to
147-
// be benign in our implementation.
148-
//
149-
// - `_LIBCPP_ASSERT_SEMANTIC_REQUIREMENT` -- checks that the given argument satisfies the semantic requirements imposed
150-
// by the Standard. Typically, there is no simple way to completely prove that a semantic requirement is satisfied;
151-
// thus, this would often be a heuristic check and it might be quite expensive.
152-
//
153-
// - `_LIBCPP_ASSERT_INTERNAL` -- checks that internal invariants of the library hold. These assertions don't depend on
154-
// user input.
155-
//
156-
// - `_LIBCPP_ASSERT_UNCATEGORIZED` -- for assertions that haven't been properly classified yet.
157-
158-
// clang-format off
159-
# define _LIBCPP_HARDENING_MODE_NONE (1 << 1)
160-
# define _LIBCPP_HARDENING_MODE_FAST (1 << 2)
161-
# define _LIBCPP_HARDENING_MODE_EXTENSIVE (1 << 4) // Deliberately not ordered.
162-
# define _LIBCPP_HARDENING_MODE_DEBUG (1 << 3)
163-
// clang-format on
164-
165-
# ifndef _LIBCPP_HARDENING_MODE
166-
167-
# ifndef _LIBCPP_HARDENING_MODE_DEFAULT
168-
# error _LIBCPP_HARDENING_MODE_DEFAULT is not defined. This definition should be set at configuration time in the \
169-
`__config_site` header, please make sure your installation of libc++ is not broken.
170-
# endif
171-
172-
# define _LIBCPP_HARDENING_MODE _LIBCPP_HARDENING_MODE_DEFAULT
173-
# endif
174-
175-
# if _LIBCPP_HARDENING_MODE != _LIBCPP_HARDENING_MODE_NONE && \
176-
_LIBCPP_HARDENING_MODE != _LIBCPP_HARDENING_MODE_FAST && \
177-
_LIBCPP_HARDENING_MODE != _LIBCPP_HARDENING_MODE_EXTENSIVE && \
178-
_LIBCPP_HARDENING_MODE != _LIBCPP_HARDENING_MODE_DEBUG
179-
# error _LIBCPP_HARDENING_MODE must be set to one of the following values: \
180-
_LIBCPP_HARDENING_MODE_NONE, \
181-
_LIBCPP_HARDENING_MODE_FAST, \
182-
_LIBCPP_HARDENING_MODE_EXTENSIVE, \
183-
_LIBCPP_HARDENING_MODE_DEBUG
184-
# endif
185-
186-
// Hardening assertion semantics generally mirror the evaluation semantics of C++26 Contracts:
187-
// - `ignore` evaluates the assertion but doesn't do anything if it fails (note that it differs from the Contracts
188-
// `ignore` semantic which wouldn't evaluate the assertion at all);
189-
// - `observe` logs an error (indicating, if possible, that the error is fatal) and continues execution;
190-
// - `quick-enforce` terminates the program as fast as possible (via trapping);
191-
// - `enforce` logs an error and then terminates the program.
192-
//
193-
// Notes:
194-
// - Continuing execution after a hardening check fails results in undefined behavior; the `observe` semantic is meant
195-
// to make adopting hardening easier but should not be used outside of this scenario;
196-
// - C++26 wording for Library Hardening precludes a conforming Hardened implementation from using the Contracts
197-
// `ignore` semantic when evaluating hardened preconditions in the Library. Libc++ allows using this semantic for
198-
// hardened preconditions, however, be aware that using `ignore` does not produce a conforming "Hardened"
199-
// implementation, unlike the other semantics above.
200-
// clang-format off
201-
# define _LIBCPP_ASSERTION_SEMANTIC_IGNORE (1 << 1)
202-
# define _LIBCPP_ASSERTION_SEMANTIC_OBSERVE (1 << 2)
203-
# define _LIBCPP_ASSERTION_SEMANTIC_QUICK_ENFORCE (1 << 3)
204-
# define _LIBCPP_ASSERTION_SEMANTIC_ENFORCE (1 << 4)
205-
// clang-format on
206-
207-
// Allow users to define an arbitrary assertion semantic; otherwise, use the default mapping from modes to semantics.
208-
// The default is for production-capable modes to use `quick-enforce` (i.e., trap) and for the `debug` mode to use
209-
// `enforce` (i.e., log and abort).
210-
# ifndef _LIBCPP_ASSERTION_SEMANTIC
211-
212-
# if _LIBCPP_HARDENING_MODE == _LIBCPP_HARDENING_MODE_DEBUG
213-
# define _LIBCPP_ASSERTION_SEMANTIC _LIBCPP_ASSERTION_SEMANTIC_ENFORCE
214-
# else
215-
# define _LIBCPP_ASSERTION_SEMANTIC _LIBCPP_ASSERTION_SEMANTIC_QUICK_ENFORCE
216-
# endif
217-
218-
# else
219-
# if !_LIBCPP_HAS_EXPERIMENTAL_LIBRARY
220-
# error "Assertion semantics are an experimental feature."
221-
# endif
222-
# if defined(_LIBCPP_CXX03_LANG)
223-
# error "Assertion semantics are not available in the C++03 mode."
224-
# endif
225-
226-
# endif // _LIBCPP_ASSERTION_SEMANTIC
227-
228-
// } HARDENING
229-
23043
# define _LIBCPP_TOSTRING2(x) #x
23144
# define _LIBCPP_TOSTRING(x) _LIBCPP_TOSTRING2(x)
23245

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
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_EXPERIMENTAL_H
10+
#define _LIBCPP___CONFIGURATION_EXPERIMENTAL_H
11+
12+
#include <__config_site>
13+
14+
#ifndef _LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER
15+
# pragma GCC system_header
16+
#endif
17+
18+
#if __has_feature(experimental_library)
19+
# ifndef _LIBCPP_ENABLE_EXPERIMENTAL
20+
# define _LIBCPP_ENABLE_EXPERIMENTAL
21+
# endif
22+
#endif
23+
24+
// Incomplete features get their own specific disabling flags. This makes it
25+
// easier to grep for target specific flags once the feature is complete.
26+
#if defined(_LIBCPP_ENABLE_EXPERIMENTAL) || defined(_LIBCPP_BUILDING_LIBRARY)
27+
# define _LIBCPP_HAS_EXPERIMENTAL_LIBRARY 1
28+
#else
29+
# define _LIBCPP_HAS_EXPERIMENTAL_LIBRARY 0
30+
#endif
31+
32+
#define _LIBCPP_HAS_EXPERIMENTAL_PSTL _LIBCPP_HAS_EXPERIMENTAL_LIBRARY
33+
#define _LIBCPP_HAS_EXPERIMENTAL_TZDB _LIBCPP_HAS_EXPERIMENTAL_LIBRARY
34+
#define _LIBCPP_HAS_EXPERIMENTAL_SYNCSTREAM _LIBCPP_HAS_EXPERIMENTAL_LIBRARY
35+
#define _LIBCPP_HAS_EXPERIMENTAL_HARDENING_OBSERVE_SEMANTIC _LIBCPP_HAS_EXPERIMENTAL_LIBRARY
36+
37+
#endif // _LIBCPP___CONFIGURATION_EXPERIMENTAL_H

0 commit comments

Comments
 (0)