[libc++] Split macros related to hardening into their own header (#167069)
Hardening macros are easy to extract into their own header, and doing so decreases the complexity of the main __config file.
This commit is contained in:
1 parent
911d1c2a24
commit
d2521f14a7
6 files changed
+227
-189
No files matched your search
@@ -328,6 +328,8 @@ set(files
|
||||
__configuration/abi.h
|
||||
__configuration/availability.h
|
||||
__configuration/compiler.h
|
||||
__configuration/experimental.h
|
||||
__configuration/hardening.h
|
||||
__configuration/language.h
|
||||
__configuration/platform.h
|
||||
__coroutine/coroutine_handle.h
|
||||
|
||||
+2
-189
@@ -14,6 +14,8 @@
|
||||
#include <__configuration/abi.h>
|
||||
#include <__configuration/availability.h>
|
||||
#include <__configuration/compiler.h>
|
||||
#include <__configuration/experimental.h>
|
||||
#include <__configuration/hardening.h>
|
||||
#include <__configuration/language.h>
|
||||
#include <__configuration/platform.h>
|
||||
|
||||
@@ -38,195 +40,6 @@
|
||||
# define _LIBCPP_FREESTANDING
|
||||
# endif
|
||||
|
||||
// NOLINTNEXTLINE(libcpp-cpp-version-check)
|
||||
# if __cplusplus < 201103L
|
||||
# define _LIBCPP_CXX03_LANG
|
||||
# endif
|
||||
|
||||
# if __has_feature(experimental_library)
|
||||
# ifndef _LIBCPP_ENABLE_EXPERIMENTAL
|
||||
# define _LIBCPP_ENABLE_EXPERIMENTAL
|
||||
# endif
|
||||
# endif
|
||||
|
||||
// Incomplete features get their own specific disabling flags. This makes it
|
||||
// easier to grep for target specific flags once the feature is complete.
|
||||
# if defined(_LIBCPP_ENABLE_EXPERIMENTAL) || defined(_LIBCPP_BUILDING_LIBRARY)
|
||||
# define _LIBCPP_HAS_EXPERIMENTAL_LIBRARY 1
|
||||
# else
|
||||
# define _LIBCPP_HAS_EXPERIMENTAL_LIBRARY 0
|
||||
# endif
|
||||
|
||||
# define _LIBCPP_HAS_EXPERIMENTAL_PSTL _LIBCPP_HAS_EXPERIMENTAL_LIBRARY
|
||||
# define _LIBCPP_HAS_EXPERIMENTAL_TZDB _LIBCPP_HAS_EXPERIMENTAL_LIBRARY
|
||||
# define _LIBCPP_HAS_EXPERIMENTAL_SYNCSTREAM _LIBCPP_HAS_EXPERIMENTAL_LIBRARY
|
||||
# define _LIBCPP_HAS_EXPERIMENTAL_HARDENING_OBSERVE_SEMANTIC _LIBCPP_HAS_EXPERIMENTAL_LIBRARY
|
||||
|
||||
// HARDENING {
|
||||
|
||||
// TODO(LLVM 23): Remove this. We're making these an error to catch folks who might not have migrated.
|
||||
// Since hardening went through several changes (many of which impacted user-facing macros),
|
||||
// we're keeping these checks around for a bit longer than usual. Failure to properly configure
|
||||
// hardening results in checks being dropped silently, which is a pretty big deal.
|
||||
# if defined(_LIBCPP_ENABLE_ASSERTIONS)
|
||||
# error "_LIBCPP_ENABLE_ASSERTIONS has been removed, please use _LIBCPP_HARDENING_MODE=<mode> instead (see docs)"
|
||||
# endif
|
||||
# if defined(_LIBCPP_ENABLE_HARDENED_MODE)
|
||||
# error "_LIBCPP_ENABLE_HARDENED_MODE has been removed, please use _LIBCPP_HARDENING_MODE=<mode> instead (see docs)"
|
||||
# endif
|
||||
# if defined(_LIBCPP_ENABLE_SAFE_MODE)
|
||||
# error "_LIBCPP_ENABLE_SAFE_MODE has been removed, please use _LIBCPP_HARDENING_MODE=<mode> instead (see docs)"
|
||||
# endif
|
||||
# if defined(_LIBCPP_ENABLE_DEBUG_MODE)
|
||||
# error "_LIBCPP_ENABLE_DEBUG_MODE has been removed, please use _LIBCPP_HARDENING_MODE=<mode> instead (see docs)"
|
||||
# endif
|
||||
|
||||
// The library provides the macro `_LIBCPP_HARDENING_MODE` which can be set to one of the following values:
|
||||
//
|
||||
// - `_LIBCPP_HARDENING_MODE_NONE`;
|
||||
// - `_LIBCPP_HARDENING_MODE_FAST`;
|
||||
// - `_LIBCPP_HARDENING_MODE_EXTENSIVE`;
|
||||
// - `_LIBCPP_HARDENING_MODE_DEBUG`.
|
||||
//
|
||||
// These values have the following effects:
|
||||
//
|
||||
// - `_LIBCPP_HARDENING_MODE_NONE` -- sets the hardening mode to "none" which disables all runtime hardening checks;
|
||||
//
|
||||
// - `_LIBCPP_HARDENING_MODE_FAST` -- sets that hardening mode to "fast". The fast mode enables security-critical checks
|
||||
// that can be done with relatively little runtime overhead in constant time;
|
||||
//
|
||||
// - `_LIBCPP_HARDENING_MODE_EXTENSIVE` -- sets the hardening mode to "extensive". The extensive mode is a superset of
|
||||
// the fast mode that additionally enables checks that are relatively cheap and prevent common types of logic errors
|
||||
// but are not necessarily security-critical;
|
||||
//
|
||||
// - `_LIBCPP_HARDENING_MODE_DEBUG` -- sets the hardening mode to "debug". The debug mode is a superset of the extensive
|
||||
// mode and enables all checks available in the library, including internal assertions. Checks that are part of the
|
||||
// debug mode can be very expensive and thus the debug mode is intended to be used for testing, not in production.
|
||||
|
||||
// Inside the library, assertions are categorized so they can be cherry-picked based on the chosen hardening mode. These
|
||||
// macros are only for internal use -- users should only pick one of the high-level hardening modes described above.
|
||||
//
|
||||
// - `_LIBCPP_ASSERT_VALID_INPUT_RANGE` -- checks that ranges (whether expressed as an iterator pair, an iterator and
|
||||
// a sentinel, an iterator and a count, or a `std::range`) given as input to library functions are valid:
|
||||
// - the sentinel is reachable from the begin iterator;
|
||||
// - TODO(hardening): both iterators refer to the same container.
|
||||
//
|
||||
// - `_LIBCPP_ASSERT_VALID_ELEMENT_ACCESS` -- checks that any attempts to access a container element, whether through
|
||||
// the container object or through an iterator, are valid and do not attempt to go out of bounds or otherwise access
|
||||
// a non-existent element. For iterator checks to work, bounded iterators must be enabled in the ABI. Types like
|
||||
// `optional` and `function` are considered one-element containers for the purposes of this check.
|
||||
//
|
||||
// - `_LIBCPP_ASSERT_NON_NULL` -- checks that the pointer being dereferenced is not null. On most modern platforms zero
|
||||
// address does not refer to an actual location in memory, so a null pointer dereference would not compromize the
|
||||
// memory security of a program (however, it is still undefined behavior that can result in strange errors due to
|
||||
// compiler optimizations).
|
||||
//
|
||||
// - `_LIBCPP_ASSERT_NON_OVERLAPPING_RANGES` -- for functions that take several ranges as arguments, checks that the
|
||||
// given ranges do not overlap.
|
||||
//
|
||||
// - `_LIBCPP_ASSERT_VALID_DEALLOCATION` -- checks that an attempt to deallocate memory is valid (e.g. the given object
|
||||
// was allocated by the given allocator). Violating this category typically results in a memory leak.
|
||||
//
|
||||
// - `_LIBCPP_ASSERT_VALID_EXTERNAL_API_CALL` -- checks that a call to an external API doesn't fail in
|
||||
// an unexpected manner. This includes triggering documented cases of undefined behavior in an external library (like
|
||||
// attempting to unlock an unlocked mutex in pthreads). Any API external to the library falls under this category
|
||||
// (from system calls to compiler intrinsics). We generally don't expect these failures to compromize memory safety or
|
||||
// otherwise create an immediate security issue.
|
||||
//
|
||||
// - `_LIBCPP_ASSERT_COMPATIBLE_ALLOCATOR` -- checks any operations that exchange nodes between containers to make sure
|
||||
// the containers have compatible allocators.
|
||||
//
|
||||
// - `_LIBCPP_ASSERT_ARGUMENT_WITHIN_DOMAIN` -- checks that the given argument is within the domain of valid arguments
|
||||
// for the function. Violating this typically produces an incorrect result (e.g. the clamp algorithm returns the
|
||||
// original value without clamping it due to incorrect functors) or puts an object into an invalid state (e.g.
|
||||
// a string view where only a subset of elements is possible to access). This category is for assertions violating
|
||||
// which doesn't cause any immediate issues in the library -- whatever the consequences are, they will happen in the
|
||||
// user code.
|
||||
//
|
||||
// - `_LIBCPP_ASSERT_PEDANTIC` -- checks prerequisites which are imposed by the Standard, but violating which happens to
|
||||
// be benign in our implementation.
|
||||
//
|
||||
// - `_LIBCPP_ASSERT_SEMANTIC_REQUIREMENT` -- checks that the given argument satisfies the semantic requirements imposed
|
||||
// by the Standard. Typically, there is no simple way to completely prove that a semantic requirement is satisfied;
|
||||
// thus, this would often be a heuristic check and it might be quite expensive.
|
||||
//
|
||||
// - `_LIBCPP_ASSERT_INTERNAL` -- checks that internal invariants of the library hold. These assertions don't depend on
|
||||
// user input.
|
||||
//
|
||||
// - `_LIBCPP_ASSERT_UNCATEGORIZED` -- for assertions that haven't been properly classified yet.
|
||||
|
||||
// clang-format off
|
||||
# define _LIBCPP_HARDENING_MODE_NONE (1 << 1)
|
||||
# define _LIBCPP_HARDENING_MODE_FAST (1 << 2)
|
||||
# define _LIBCPP_HARDENING_MODE_EXTENSIVE (1 << 4) // Deliberately not ordered.
|
||||
# define _LIBCPP_HARDENING_MODE_DEBUG (1 << 3)
|
||||
// clang-format on
|
||||
|
||||
# ifndef _LIBCPP_HARDENING_MODE
|
||||
|
||||
# ifndef _LIBCPP_HARDENING_MODE_DEFAULT
|
||||
# error _LIBCPP_HARDENING_MODE_DEFAULT is not defined. This definition should be set at configuration time in the \
|
||||
`__config_site` header, please make sure your installation of libc++ is not broken.
|
||||
# endif
|
||||
|
||||
# define _LIBCPP_HARDENING_MODE _LIBCPP_HARDENING_MODE_DEFAULT
|
||||
# endif
|
||||
|
||||
# if _LIBCPP_HARDENING_MODE != _LIBCPP_HARDENING_MODE_NONE && \
|
||||
_LIBCPP_HARDENING_MODE != _LIBCPP_HARDENING_MODE_FAST && \
|
||||
_LIBCPP_HARDENING_MODE != _LIBCPP_HARDENING_MODE_EXTENSIVE && \
|
||||
_LIBCPP_HARDENING_MODE != _LIBCPP_HARDENING_MODE_DEBUG
|
||||
# error _LIBCPP_HARDENING_MODE must be set to one of the following values: \
|
||||
_LIBCPP_HARDENING_MODE_NONE, \
|
||||
_LIBCPP_HARDENING_MODE_FAST, \
|
||||
_LIBCPP_HARDENING_MODE_EXTENSIVE, \
|
||||
_LIBCPP_HARDENING_MODE_DEBUG
|
||||
# endif
|
||||
|
||||
// Hardening assertion semantics generally mirror the evaluation semantics of C++26 Contracts:
|
||||
// - `ignore` evaluates the assertion but doesn't do anything if it fails (note that it differs from the Contracts
|
||||
// `ignore` semantic which wouldn't evaluate the assertion at all);
|
||||
// - `observe` logs an error (indicating, if possible, that the error is fatal) and continues execution;
|
||||
// - `quick-enforce` terminates the program as fast as possible (via trapping);
|
||||
// - `enforce` logs an error and then terminates the program.
|
||||
//
|
||||
// Notes:
|
||||
// - Continuing execution after a hardening check fails results in undefined behavior; the `observe` semantic is meant
|
||||
// to make adopting hardening easier but should not be used outside of this scenario;
|
||||
// - C++26 wording for Library Hardening precludes a conforming Hardened implementation from using the Contracts
|
||||
// `ignore` semantic when evaluating hardened preconditions in the Library. Libc++ allows using this semantic for
|
||||
// hardened preconditions, however, be aware that using `ignore` does not produce a conforming "Hardened"
|
||||
// implementation, unlike the other semantics above.
|
||||
// clang-format off
|
||||
# define _LIBCPP_ASSERTION_SEMANTIC_IGNORE (1 << 1)
|
||||
# define _LIBCPP_ASSERTION_SEMANTIC_OBSERVE (1 << 2)
|
||||
# define _LIBCPP_ASSERTION_SEMANTIC_QUICK_ENFORCE (1 << 3)
|
||||
# define _LIBCPP_ASSERTION_SEMANTIC_ENFORCE (1 << 4)
|
||||
// clang-format on
|
||||
|
||||
// Allow users to define an arbitrary assertion semantic; otherwise, use the default mapping from modes to semantics.
|
||||
// The default is for production-capable modes to use `quick-enforce` (i.e., trap) and for the `debug` mode to use
|
||||
// `enforce` (i.e., log and abort).
|
||||
# ifndef _LIBCPP_ASSERTION_SEMANTIC
|
||||
|
||||
# if _LIBCPP_HARDENING_MODE == _LIBCPP_HARDENING_MODE_DEBUG
|
||||
# define _LIBCPP_ASSERTION_SEMANTIC _LIBCPP_ASSERTION_SEMANTIC_ENFORCE
|
||||
# else
|
||||
# define _LIBCPP_ASSERTION_SEMANTIC _LIBCPP_ASSERTION_SEMANTIC_QUICK_ENFORCE
|
||||
# endif
|
||||
|
||||
# else
|
||||
# if !_LIBCPP_HAS_EXPERIMENTAL_LIBRARY
|
||||
# error "Assertion semantics are an experimental feature."
|
||||
# endif
|
||||
# if defined(_LIBCPP_CXX03_LANG)
|
||||
# error "Assertion semantics are not available in the C++03 mode."
|
||||
# endif
|
||||
|
||||
# endif // _LIBCPP_ASSERTION_SEMANTIC
|
||||
|
||||
// } HARDENING
|
||||
|
||||
# define _LIBCPP_TOSTRING2(x) #x
|
||||
# define _LIBCPP_TOSTRING(x) _LIBCPP_TOSTRING2(x)
|
||||
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef _LIBCPP___CONFIGURATION_EXPERIMENTAL_H
|
||||
#define _LIBCPP___CONFIGURATION_EXPERIMENTAL_H
|
||||
|
||||
#include <__config_site>
|
||||
|
||||
#ifndef _LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER
|
||||
# pragma GCC system_header
|
||||
#endif
|
||||
|
||||
#if __has_feature(experimental_library)
|
||||
# ifndef _LIBCPP_ENABLE_EXPERIMENTAL
|
||||
# define _LIBCPP_ENABLE_EXPERIMENTAL
|
||||
# endif
|
||||
#endif
|
||||
|
||||
// Incomplete features get their own specific disabling flags. This makes it
|
||||
// easier to grep for target specific flags once the feature is complete.
|
||||
#if defined(_LIBCPP_ENABLE_EXPERIMENTAL) || defined(_LIBCPP_BUILDING_LIBRARY)
|
||||
# define _LIBCPP_HAS_EXPERIMENTAL_LIBRARY 1
|
||||
#else
|
||||
# define _LIBCPP_HAS_EXPERIMENTAL_LIBRARY 0
|
||||
#endif
|
||||
|
||||
#define _LIBCPP_HAS_EXPERIMENTAL_PSTL _LIBCPP_HAS_EXPERIMENTAL_LIBRARY
|
||||
#define _LIBCPP_HAS_EXPERIMENTAL_TZDB _LIBCPP_HAS_EXPERIMENTAL_LIBRARY
|
||||
#define _LIBCPP_HAS_EXPERIMENTAL_SYNCSTREAM _LIBCPP_HAS_EXPERIMENTAL_LIBRARY
|
||||
#define _LIBCPP_HAS_EXPERIMENTAL_HARDENING_OBSERVE_SEMANTIC _LIBCPP_HAS_EXPERIMENTAL_LIBRARY
|
||||
|
||||
#endif // _LIBCPP___CONFIGURATION_EXPERIMENTAL_H
|
||||
@@ -0,0 +1,181 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef _LIBCPP___CONFIGURATION_HARDENING_H
|
||||
#define _LIBCPP___CONFIGURATION_HARDENING_H
|
||||
|
||||
#include <__config_site>
|
||||
#include <__configuration/experimental.h>
|
||||
#include <__configuration/language.h>
|
||||
|
||||
#ifndef _LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER
|
||||
# pragma GCC system_header
|
||||
#endif
|
||||
|
||||
// TODO(LLVM 23): Remove this. We're making these an error to catch folks who might not have migrated.
|
||||
// Since hardening went through several changes (many of which impacted user-facing macros),
|
||||
// we're keeping these checks around for a bit longer than usual. Failure to properly configure
|
||||
// hardening results in checks being dropped silently, which is a pretty big deal.
|
||||
#if defined(_LIBCPP_ENABLE_ASSERTIONS)
|
||||
# error "_LIBCPP_ENABLE_ASSERTIONS has been removed, please use _LIBCPP_HARDENING_MODE=<mode> instead (see docs)"
|
||||
#endif
|
||||
#if defined(_LIBCPP_ENABLE_HARDENED_MODE)
|
||||
# error "_LIBCPP_ENABLE_HARDENED_MODE has been removed, please use _LIBCPP_HARDENING_MODE=<mode> instead (see docs)"
|
||||
#endif
|
||||
#if defined(_LIBCPP_ENABLE_SAFE_MODE)
|
||||
# error "_LIBCPP_ENABLE_SAFE_MODE has been removed, please use _LIBCPP_HARDENING_MODE=<mode> instead (see docs)"
|
||||
#endif
|
||||
#if defined(_LIBCPP_ENABLE_DEBUG_MODE)
|
||||
# error "_LIBCPP_ENABLE_DEBUG_MODE has been removed, please use _LIBCPP_HARDENING_MODE=<mode> instead (see docs)"
|
||||
#endif
|
||||
|
||||
// The library provides the macro `_LIBCPP_HARDENING_MODE` which can be set to one of the following values:
|
||||
//
|
||||
// - `_LIBCPP_HARDENING_MODE_NONE`;
|
||||
// - `_LIBCPP_HARDENING_MODE_FAST`;
|
||||
// - `_LIBCPP_HARDENING_MODE_EXTENSIVE`;
|
||||
// - `_LIBCPP_HARDENING_MODE_DEBUG`.
|
||||
//
|
||||
// These values have the following effects:
|
||||
//
|
||||
// - `_LIBCPP_HARDENING_MODE_NONE` -- sets the hardening mode to "none" which disables all runtime hardening checks;
|
||||
//
|
||||
// - `_LIBCPP_HARDENING_MODE_FAST` -- sets that hardening mode to "fast". The fast mode enables security-critical checks
|
||||
// that can be done with relatively little runtime overhead in constant time;
|
||||
//
|
||||
// - `_LIBCPP_HARDENING_MODE_EXTENSIVE` -- sets the hardening mode to "extensive". The extensive mode is a superset of
|
||||
// the fast mode that additionally enables checks that are relatively cheap and prevent common types of logic errors
|
||||
// but are not necessarily security-critical;
|
||||
//
|
||||
// - `_LIBCPP_HARDENING_MODE_DEBUG` -- sets the hardening mode to "debug". The debug mode is a superset of the extensive
|
||||
// mode and enables all checks available in the library, including internal assertions. Checks that are part of the
|
||||
// debug mode can be very expensive and thus the debug mode is intended to be used for testing, not in production.
|
||||
|
||||
// Inside the library, assertions are categorized so they can be cherry-picked based on the chosen hardening mode. These
|
||||
// macros are only for internal use -- users should only pick one of the high-level hardening modes described above.
|
||||
//
|
||||
// - `_LIBCPP_ASSERT_VALID_INPUT_RANGE` -- checks that ranges (whether expressed as an iterator pair, an iterator and
|
||||
// a sentinel, an iterator and a count, or a `std::range`) given as input to library functions are valid:
|
||||
// - the sentinel is reachable from the begin iterator;
|
||||
// - TODO(hardening): both iterators refer to the same container.
|
||||
//
|
||||
// - `_LIBCPP_ASSERT_VALID_ELEMENT_ACCESS` -- checks that any attempts to access a container element, whether through
|
||||
// the container object or through an iterator, are valid and do not attempt to go out of bounds or otherwise access
|
||||
// a non-existent element. For iterator checks to work, bounded iterators must be enabled in the ABI. Types like
|
||||
// `optional` and `function` are considered one-element containers for the purposes of this check.
|
||||
//
|
||||
// - `_LIBCPP_ASSERT_NON_NULL` -- checks that the pointer being dereferenced is not null. On most modern platforms zero
|
||||
// address does not refer to an actual location in memory, so a null pointer dereference would not compromize the
|
||||
// memory security of a program (however, it is still undefined behavior that can result in strange errors due to
|
||||
// compiler optimizations).
|
||||
//
|
||||
// - `_LIBCPP_ASSERT_NON_OVERLAPPING_RANGES` -- for functions that take several ranges as arguments, checks that the
|
||||
// given ranges do not overlap.
|
||||
//
|
||||
// - `_LIBCPP_ASSERT_VALID_DEALLOCATION` -- checks that an attempt to deallocate memory is valid (e.g. the given object
|
||||
// was allocated by the given allocator). Violating this category typically results in a memory leak.
|
||||
//
|
||||
// - `_LIBCPP_ASSERT_VALID_EXTERNAL_API_CALL` -- checks that a call to an external API doesn't fail in
|
||||
// an unexpected manner. This includes triggering documented cases of undefined behavior in an external library (like
|
||||
// attempting to unlock an unlocked mutex in pthreads). Any API external to the library falls under this category
|
||||
// (from system calls to compiler intrinsics). We generally don't expect these failures to compromize memory safety or
|
||||
// otherwise create an immediate security issue.
|
||||
//
|
||||
// - `_LIBCPP_ASSERT_COMPATIBLE_ALLOCATOR` -- checks any operations that exchange nodes between containers to make sure
|
||||
// the containers have compatible allocators.
|
||||
//
|
||||
// - `_LIBCPP_ASSERT_ARGUMENT_WITHIN_DOMAIN` -- checks that the given argument is within the domain of valid arguments
|
||||
// for the function. Violating this typically produces an incorrect result (e.g. the clamp algorithm returns the
|
||||
// original value without clamping it due to incorrect functors) or puts an object into an invalid state (e.g.
|
||||
// a string view where only a subset of elements is possible to access). This category is for assertions violating
|
||||
// which doesn't cause any immediate issues in the library -- whatever the consequences are, they will happen in the
|
||||
// user code.
|
||||
//
|
||||
// - `_LIBCPP_ASSERT_PEDANTIC` -- checks prerequisites which are imposed by the Standard, but violating which happens to
|
||||
// be benign in our implementation.
|
||||
//
|
||||
// - `_LIBCPP_ASSERT_SEMANTIC_REQUIREMENT` -- checks that the given argument satisfies the semantic requirements imposed
|
||||
// by the Standard. Typically, there is no simple way to completely prove that a semantic requirement is satisfied;
|
||||
// thus, this would often be a heuristic check and it might be quite expensive.
|
||||
//
|
||||
// - `_LIBCPP_ASSERT_INTERNAL` -- checks that internal invariants of the library hold. These assertions don't depend on
|
||||
// user input.
|
||||
//
|
||||
// - `_LIBCPP_ASSERT_UNCATEGORIZED` -- for assertions that haven't been properly classified yet.
|
||||
|
||||
// clang-format off
|
||||
# define _LIBCPP_HARDENING_MODE_NONE (1 << 1)
|
||||
# define _LIBCPP_HARDENING_MODE_FAST (1 << 2)
|
||||
# define _LIBCPP_HARDENING_MODE_EXTENSIVE (1 << 4) // Deliberately not ordered.
|
||||
# define _LIBCPP_HARDENING_MODE_DEBUG (1 << 3)
|
||||
// clang-format on
|
||||
|
||||
#ifndef _LIBCPP_HARDENING_MODE
|
||||
|
||||
# ifndef _LIBCPP_HARDENING_MODE_DEFAULT
|
||||
# error _LIBCPP_HARDENING_MODE_DEFAULT is not defined. This definition should be set at configuration time in the \
|
||||
`__config_site` header, please make sure your installation of libc++ is not broken.
|
||||
# endif
|
||||
|
||||
# define _LIBCPP_HARDENING_MODE _LIBCPP_HARDENING_MODE_DEFAULT
|
||||
#endif
|
||||
|
||||
#if _LIBCPP_HARDENING_MODE != _LIBCPP_HARDENING_MODE_NONE && _LIBCPP_HARDENING_MODE != _LIBCPP_HARDENING_MODE_FAST && \
|
||||
_LIBCPP_HARDENING_MODE != _LIBCPP_HARDENING_MODE_EXTENSIVE && \
|
||||
_LIBCPP_HARDENING_MODE != _LIBCPP_HARDENING_MODE_DEBUG
|
||||
# error _LIBCPP_HARDENING_MODE must be set to one of the following values: \
|
||||
_LIBCPP_HARDENING_MODE_NONE, \
|
||||
_LIBCPP_HARDENING_MODE_FAST, \
|
||||
_LIBCPP_HARDENING_MODE_EXTENSIVE, \
|
||||
_LIBCPP_HARDENING_MODE_DEBUG
|
||||
#endif
|
||||
|
||||
// Hardening assertion semantics generally mirror the evaluation semantics of C++26 Contracts:
|
||||
// - `ignore` evaluates the assertion but doesn't do anything if it fails (note that it differs from the Contracts
|
||||
// `ignore` semantic which wouldn't evaluate the assertion at all);
|
||||
// - `observe` logs an error (indicating, if possible, that the error is fatal) and continues execution;
|
||||
// - `quick-enforce` terminates the program as fast as possible (via trapping);
|
||||
// - `enforce` logs an error and then terminates the program.
|
||||
//
|
||||
// Notes:
|
||||
// - Continuing execution after a hardening check fails results in undefined behavior; the `observe` semantic is meant
|
||||
// to make adopting hardening easier but should not be used outside of this scenario;
|
||||
// - C++26 wording for Library Hardening precludes a conforming Hardened implementation from using the Contracts
|
||||
// `ignore` semantic when evaluating hardened preconditions in the Library. Libc++ allows using this semantic for
|
||||
// hardened preconditions, however, be aware that using `ignore` does not produce a conforming "Hardened"
|
||||
// implementation, unlike the other semantics above.
|
||||
// clang-format off
|
||||
# define _LIBCPP_ASSERTION_SEMANTIC_IGNORE (1 << 1)
|
||||
# define _LIBCPP_ASSERTION_SEMANTIC_OBSERVE (1 << 2)
|
||||
# define _LIBCPP_ASSERTION_SEMANTIC_QUICK_ENFORCE (1 << 3)
|
||||
# define _LIBCPP_ASSERTION_SEMANTIC_ENFORCE (1 << 4)
|
||||
// clang-format on
|
||||
|
||||
// Allow users to define an arbitrary assertion semantic; otherwise, use the default mapping from modes to semantics.
|
||||
// The default is for production-capable modes to use `quick-enforce` (i.e., trap) and for the `debug` mode to use
|
||||
// `enforce` (i.e., log and abort).
|
||||
#ifndef _LIBCPP_ASSERTION_SEMANTIC
|
||||
|
||||
# if _LIBCPP_HARDENING_MODE == _LIBCPP_HARDENING_MODE_DEBUG
|
||||
# define _LIBCPP_ASSERTION_SEMANTIC _LIBCPP_ASSERTION_SEMANTIC_ENFORCE
|
||||
# else
|
||||
# define _LIBCPP_ASSERTION_SEMANTIC _LIBCPP_ASSERTION_SEMANTIC_QUICK_ENFORCE
|
||||
# endif
|
||||
|
||||
#else
|
||||
|
||||
# if !_LIBCPP_HAS_EXPERIMENTAL_LIBRARY
|
||||
# error "Assertion semantics are an experimental feature."
|
||||
# endif
|
||||
# if defined(_LIBCPP_CXX03_LANG)
|
||||
# error "Assertion semantics are not available in the C++03 mode."
|
||||
# endif
|
||||
|
||||
#endif // _LIBCPP_ASSERTION_SEMANTIC
|
||||
|
||||
#endif // _LIBCPP___CONFIGURATION_HARDENING_H
|
||||
@@ -18,6 +18,9 @@
|
||||
|
||||
// NOLINTBEGIN(libcpp-cpp-version-check)
|
||||
#ifdef __cplusplus
|
||||
# if __cplusplus < 201103L
|
||||
# define _LIBCPP_CXX03_LANG
|
||||
# endif
|
||||
# if __cplusplus <= 201103L
|
||||
# define _LIBCPP_STD_VER 11
|
||||
# elif __cplusplus <= 201402L
|
||||
|
||||
@@ -6,6 +6,8 @@ module std_config [system] {
|
||||
textual header "__configuration/abi.h"
|
||||
textual header "__configuration/availability.h"
|
||||
textual header "__configuration/compiler.h"
|
||||
textual header "__configuration/experimental.h"
|
||||
textual header "__configuration/hardening.h"
|
||||
textual header "__configuration/language.h"
|
||||
textual header "__configuration/platform.h"
|
||||
textual header "version"
|
||||
|
||||
Reference in new issue
Block a user