From 4a3a6fc3aa7b2a33cd6e6de9dff30dde5c1c2992 Mon Sep 17 00:00:00 2001 From: Konstantin Varlamov Date: Tue, 11 Nov 2025 20:30:38 -0800 Subject: [PATCH 01/11] [libc++][hardening] Allow setting the assertion semantic via CMake. Add a new CMake variable, `LIBCXX_ASSERTION_SEMANTIC`, that largely mirrors `LIBCXX_HARDENING_MODE`, except that not setting it is valid and results in the default mapping from the selected hardening mode: - `fast` and `extensive` map to `quick_enforce`; - `debug` maps to `enforce`. The default assertion semantic set via CMake takes precedence over the default mapping but can still be overridden by setting the `_LIBCPP_ASSERTION_SEMANTIC` macro directly. --- libcxx/CMakeLists.txt | 21 ++++ libcxx/include/__config_site.in | 1 + libcxx/include/__configuration/hardening.h | 128 ++++++++++++--------- 3 files changed, 97 insertions(+), 53 deletions(-) diff --git a/libcxx/CMakeLists.txt b/libcxx/CMakeLists.txt index a119850cd808e..ed577efc9dda8 100644 --- a/libcxx/CMakeLists.txt +++ b/libcxx/CMakeLists.txt @@ -66,6 +66,18 @@ if (NOT "${LIBCXX_HARDENING_MODE}" IN_LIST LIBCXX_SUPPORTED_HARDENING_MODES) message(FATAL_ERROR "Unsupported hardening mode: '${LIBCXX_HARDENING_MODE}'. Supported values are ${LIBCXX_SUPPORTED_HARDENING_MODES}.") endif() +set(LIBCXX_SUPPORTED_ASSERTION_SEMANTICS ignore observe quick_enforce enforce) +set(LIBCXX_ASSERTION_SEMANTIC "" CACHE STRING + "Specify the default assertion semantic to use. This semantic will be used + inside the compiled library and will be the default when compiling user code. + If not defined, the library will select the assertion semantic based on the hardening + mode in effect. Note that users can override this setting in their own code. + This does not affect the ABI. Supported values are + ${LIBCXX_SUPPORTED_ASSERTION_SEMANTICS}.") +if ("${LIBCXX_ASSERTION_SEMANTIC}" AND NOT "${LIBCXX_ASSERTION_SEMANTIC}" IN_LIST LIBCXX_SUPPORTED_ASSERTION_SEMANTICS) + message(FATAL_ERROR + "Unsupported assertion semantic: '${LIBCXX_ASSERTION_SEMANTIC}'. Supported values are ${LIBCXX_SUPPORTED_ASSERTION_SEMANTICS}.") +endif() set(LIBCXX_ASSERTION_HANDLER_FILE "vendor/llvm/default_assertion_handler.in" CACHE STRING @@ -763,6 +775,15 @@ elseif (LIBCXX_HARDENING_MODE STREQUAL "extensive") elseif (LIBCXX_HARDENING_MODE STREQUAL "debug") config_define(8 _LIBCPP_HARDENING_MODE_DEFAULT) endif() +if (LIBCXX_ASSERTION_SEMANTIC STREQUAL "ignore") + config_define(2 _LIBCPP_ASSERTION_SEMANTIC_DEFAULT) +elseif (LIBCXX_ASSERTION_SEMANTIC STREQUAL "observe") + config_define(4 _LIBCPP_ASSERTION_SEMANTIC_DEFAULT) +elseif (LIBCXX_ASSERTION_SEMANTIC STREQUAL "quick_enforce") + config_define(8 _LIBCPP_ASSERTION_SEMANTIC_DEFAULT) +elseif (LIBCXX_ASSERTION_SEMANTIC STREQUAL "enforce") + config_define(16 _LIBCPP_ASSERTION_SEMANTIC_DEFAULT) +endif() if (LIBCXX_PSTL_BACKEND STREQUAL "serial") config_define(1 _LIBCPP_PSTL_BACKEND_SERIAL) diff --git a/libcxx/include/__config_site.in b/libcxx/include/__config_site.in index b68c0c8258366..6dcca1849a96c 100644 --- a/libcxx/include/__config_site.in +++ b/libcxx/include/__config_site.in @@ -40,6 +40,7 @@ // Hardening. #cmakedefine _LIBCPP_HARDENING_MODE_DEFAULT @_LIBCPP_HARDENING_MODE_DEFAULT@ +#cmakedefine _LIBCPP_ASSERTION_SEMANTIC_DEFAULT @_LIBCPP_ASSERTION_SEMANTIC_DEFAULT@ // __USE_MINGW_ANSI_STDIO gets redefined on MinGW #ifdef __clang__ diff --git a/libcxx/include/__configuration/hardening.h b/libcxx/include/__configuration/hardening.h index bc2a8d078fa77..591a66484d780 100644 --- a/libcxx/include/__configuration/hardening.h +++ b/libcxx/include/__configuration/hardening.h @@ -7,32 +7,32 @@ //===----------------------------------------------------------------------===// #ifndef _LIBCPP___CONFIGURATION_HARDENING_H -#define _LIBCPP___CONFIGURATION_HARDENING_H +# define _LIBCPP___CONFIGURATION_HARDENING_H -#include <__config_site> -#include <__configuration/experimental.h> -#include <__configuration/language.h> +# include <__config_site> +# include <__configuration/experimental.h> +# include <__configuration/language.h> -#ifndef _LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER -# pragma GCC system_header -#endif +# 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= instead (see docs)" -#endif -#if defined(_LIBCPP_ENABLE_HARDENED_MODE) -# error "_LIBCPP_ENABLE_HARDENED_MODE has been removed, please use _LIBCPP_HARDENING_MODE= instead (see docs)" -#endif -#if defined(_LIBCPP_ENABLE_SAFE_MODE) -# error "_LIBCPP_ENABLE_SAFE_MODE has been removed, please use _LIBCPP_HARDENING_MODE= instead (see docs)" -#endif -#if defined(_LIBCPP_ENABLE_DEBUG_MODE) -# error "_LIBCPP_ENABLE_DEBUG_MODE has been removed, please use _LIBCPP_HARDENING_MODE= instead (see docs)" -#endif +# if defined(_LIBCPP_ENABLE_ASSERTIONS) +# error "_LIBCPP_ENABLE_ASSERTIONS has been removed, please use _LIBCPP_HARDENING_MODE= instead (see docs)" +# endif +# if defined(_LIBCPP_ENABLE_HARDENED_MODE) +# error "_LIBCPP_ENABLE_HARDENED_MODE has been removed, please use _LIBCPP_HARDENING_MODE= instead (see docs)" +# endif +# if defined(_LIBCPP_ENABLE_SAFE_MODE) +# error "_LIBCPP_ENABLE_SAFE_MODE has been removed, please use _LIBCPP_HARDENING_MODE= instead (see docs)" +# endif +# if defined(_LIBCPP_ENABLE_DEBUG_MODE) +# error "_LIBCPP_ENABLE_DEBUG_MODE has been removed, please use _LIBCPP_HARDENING_MODE= instead (see docs)" +# endif // The library provides the macro `_LIBCPP_HARDENING_MODE` which can be set to one of the following values: // @@ -115,25 +115,26 @@ # define _LIBCPP_HARDENING_MODE_DEBUG (1 << 3) // clang-format on -#ifndef _LIBCPP_HARDENING_MODE +# 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 \ +# 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 +# endif -# define _LIBCPP_HARDENING_MODE _LIBCPP_HARDENING_MODE_DEFAULT -#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: \ +# 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 +# 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 @@ -156,26 +157,47 @@ _LIBCPP_HARDENING_MODE_DEBUG # 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 +// If the user or the vendor attempt to configure the assertion semantic, check that it is allowed in the current +// environment. +# if defined(_LIBCPP_ASSERTION_SEMANTIC) || defined(_LIBCPP_ASSERTION_SEMANTIC_DEFAULT) +# 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 // defined(_LIBCPP_ASSERTION_SEMANTIC) || defined(_LIBCPP_ASSERTION_SEMANTIC_DEFAULT) + +// There are 2 ways to configure the assertion semantic, listed in order of precedence: +// 1. The `_LIBCPP_ASSERTION_SEMANTIC` macro, defined directly by the user. +// 2. The `LIBCXX_ASSERTION_SEMANTIC` CMake variable, set by the vendor. +// If neither `_LIBCPP_ASSERTION_SEMANTIC` nor `LIBCXX_ASSERTION_SEMANTIC` are defined, the default mapping is used +// which determines the semantic based on the hardening mode in effect: production-capable modes map to `quick-enforce` +// (i.e., trap) and the `debug` mode maps to `enforce` (i.e., log and abort). +# ifndef _LIBCPP_ASSERTION_SEMANTIC // User-provided semantic takes top priority -- don't override if set. + +# ifdef _LIBCPP_ASSERTION_SEMANTIC_DEFAULT // Vendor-provided semantic takes second priority. +# define _LIBCPP_ASSERTION_SEMANTIC _LIBCPP_ASSERTION_SEMANTIC_DEFAULT +# else // Fallback: use the default mapping. +# 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 +#endif // ifdef _LIBCPP_ASSERTION_SEMANTIC_DEFAULT + +# endif // _LIBCPP_ASSERTION_SEMANTIC + +// Finally, validate the selected semantic (in case the user tries setting it to an incorrect value): +# if _LIBCPP_ASSERTION_SEMANTIC != _LIBCPP_ASSERTION_SEMANTIC_IGNORE && \ + _LIBCPP_ASSERTION_SEMANTIC != _LIBCPP_ASSERTION_SEMANTIC_OBSERVE && \ + _LIBCPP_ASSERTION_SEMANTIC != _LIBCPP_ASSERTION_SEMANTIC_QUICK_ENFORCE && \ + _LIBCPP_ASSERTION_SEMANTIC != _LIBCPP_ASSERTION_SEMANTIC_ENFORCE +# error _LIBCPP_ASSERTION_SEMANTIC must be set to one of the following values: \ +_LIBCPP_ASSERTION_SEMANTIC_IGNORE, \ +_LIBCPP_ASSERTION_SEMANTIC_OBSERVE, \ +_LIBCPP_ASSERTION_SEMANTIC_QUICK_ENFORCE, \ +_LIBCPP_ASSERTION_SEMANTIC_ENFORCE +# endif + +# endif // _LIBCPP___CONFIGURATION_HARDENING_H From 827c6ab9964ac51874db732c6dab921d34aa928b Mon Sep 17 00:00:00 2001 From: Konstantin Varlamov Date: Tue, 11 Nov 2025 20:42:59 -0800 Subject: [PATCH 02/11] Fix the check for empty string in `CMakeLists.txt`. --- libcxx/CMakeLists.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libcxx/CMakeLists.txt b/libcxx/CMakeLists.txt index ed577efc9dda8..bebef101fcdff 100644 --- a/libcxx/CMakeLists.txt +++ b/libcxx/CMakeLists.txt @@ -74,7 +74,8 @@ set(LIBCXX_ASSERTION_SEMANTIC "" CACHE STRING mode in effect. Note that users can override this setting in their own code. This does not affect the ABI. Supported values are ${LIBCXX_SUPPORTED_ASSERTION_SEMANTICS}.") -if ("${LIBCXX_ASSERTION_SEMANTIC}" AND NOT "${LIBCXX_ASSERTION_SEMANTIC}" IN_LIST LIBCXX_SUPPORTED_ASSERTION_SEMANTICS) + +if (NOT "${LIBCXX_ASSERTION_SEMANTIC}" STREQUAL "" AND NOT "${LIBCXX_ASSERTION_SEMANTIC}" IN_LIST LIBCXX_SUPPORTED_ASSERTION_SEMANTICS) message(FATAL_ERROR "Unsupported assertion semantic: '${LIBCXX_ASSERTION_SEMANTIC}'. Supported values are ${LIBCXX_SUPPORTED_ASSERTION_SEMANTICS}.") endif() From 2a2469ba4bc897fbca32f06be812946092b0959c Mon Sep 17 00:00:00 2001 From: Konstantin Varlamov Date: Wed, 12 Nov 2025 12:46:58 -0800 Subject: [PATCH 03/11] Fix formatting. --- libcxx/include/__configuration/hardening.h | 115 ++++++++++----------- 1 file changed, 57 insertions(+), 58 deletions(-) diff --git a/libcxx/include/__configuration/hardening.h b/libcxx/include/__configuration/hardening.h index 591a66484d780..c761d36232452 100644 --- a/libcxx/include/__configuration/hardening.h +++ b/libcxx/include/__configuration/hardening.h @@ -7,32 +7,32 @@ //===----------------------------------------------------------------------===// #ifndef _LIBCPP___CONFIGURATION_HARDENING_H -# define _LIBCPP___CONFIGURATION_HARDENING_H +#define _LIBCPP___CONFIGURATION_HARDENING_H -# include <__config_site> -# include <__configuration/experimental.h> -# include <__configuration/language.h> +#include <__config_site> +#include <__configuration/experimental.h> +#include <__configuration/language.h> -# ifndef _LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER -# pragma GCC system_header -# endif +#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= instead (see docs)" -# endif -# if defined(_LIBCPP_ENABLE_HARDENED_MODE) -# error "_LIBCPP_ENABLE_HARDENED_MODE has been removed, please use _LIBCPP_HARDENING_MODE= instead (see docs)" -# endif -# if defined(_LIBCPP_ENABLE_SAFE_MODE) -# error "_LIBCPP_ENABLE_SAFE_MODE has been removed, please use _LIBCPP_HARDENING_MODE= instead (see docs)" -# endif -# if defined(_LIBCPP_ENABLE_DEBUG_MODE) -# error "_LIBCPP_ENABLE_DEBUG_MODE has been removed, please use _LIBCPP_HARDENING_MODE= instead (see docs)" -# endif +#if defined(_LIBCPP_ENABLE_ASSERTIONS) +# error "_LIBCPP_ENABLE_ASSERTIONS has been removed, please use _LIBCPP_HARDENING_MODE= instead (see docs)" +#endif +#if defined(_LIBCPP_ENABLE_HARDENED_MODE) +# error "_LIBCPP_ENABLE_HARDENED_MODE has been removed, please use _LIBCPP_HARDENING_MODE= instead (see docs)" +#endif +#if defined(_LIBCPP_ENABLE_SAFE_MODE) +# error "_LIBCPP_ENABLE_SAFE_MODE has been removed, please use _LIBCPP_HARDENING_MODE= instead (see docs)" +#endif +#if defined(_LIBCPP_ENABLE_DEBUG_MODE) +# error "_LIBCPP_ENABLE_DEBUG_MODE has been removed, please use _LIBCPP_HARDENING_MODE= instead (see docs)" +#endif // The library provides the macro `_LIBCPP_HARDENING_MODE` which can be set to one of the following values: // @@ -115,26 +115,25 @@ # define _LIBCPP_HARDENING_MODE_DEBUG (1 << 3) // clang-format on -# ifndef _LIBCPP_HARDENING_MODE +#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 \ +# 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: \ +# 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 +#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 @@ -159,14 +158,14 @@ _LIBCPP_HARDENING_MODE_DEBUG // If the user or the vendor attempt to configure the assertion semantic, check that it is allowed in the current // environment. -# if defined(_LIBCPP_ASSERTION_SEMANTIC) || defined(_LIBCPP_ASSERTION_SEMANTIC_DEFAULT) -# 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 // defined(_LIBCPP_ASSERTION_SEMANTIC) || defined(_LIBCPP_ASSERTION_SEMANTIC_DEFAULT) +#if defined(_LIBCPP_ASSERTION_SEMANTIC) || defined(_LIBCPP_ASSERTION_SEMANTIC_DEFAULT) +# 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 // defined(_LIBCPP_ASSERTION_SEMANTIC) || defined(_LIBCPP_ASSERTION_SEMANTIC_DEFAULT) // There are 2 ways to configure the assertion semantic, listed in order of precedence: // 1. The `_LIBCPP_ASSERTION_SEMANTIC` macro, defined directly by the user. @@ -174,30 +173,30 @@ _LIBCPP_HARDENING_MODE_DEBUG // If neither `_LIBCPP_ASSERTION_SEMANTIC` nor `LIBCXX_ASSERTION_SEMANTIC` are defined, the default mapping is used // which determines the semantic based on the hardening mode in effect: production-capable modes map to `quick-enforce` // (i.e., trap) and the `debug` mode maps to `enforce` (i.e., log and abort). -# ifndef _LIBCPP_ASSERTION_SEMANTIC // User-provided semantic takes top priority -- don't override if set. - -# ifdef _LIBCPP_ASSERTION_SEMANTIC_DEFAULT // Vendor-provided semantic takes second priority. -# define _LIBCPP_ASSERTION_SEMANTIC _LIBCPP_ASSERTION_SEMANTIC_DEFAULT -# else // Fallback: use the default mapping. -# 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 -#endif // ifdef _LIBCPP_ASSERTION_SEMANTIC_DEFAULT +#ifndef _LIBCPP_ASSERTION_SEMANTIC // User-provided semantic takes top priority -- don't override if set. + +# ifdef _LIBCPP_ASSERTION_SEMANTIC_DEFAULT // Vendor-provided semantic takes second priority. +# define _LIBCPP_ASSERTION_SEMANTIC _LIBCPP_ASSERTION_SEMANTIC_DEFAULT +# else // Fallback: use the default mapping. +# 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 +# endif // ifdef _LIBCPP_ASSERTION_SEMANTIC_DEFAULT -# endif // _LIBCPP_ASSERTION_SEMANTIC +#endif // _LIBCPP_ASSERTION_SEMANTIC // Finally, validate the selected semantic (in case the user tries setting it to an incorrect value): -# if _LIBCPP_ASSERTION_SEMANTIC != _LIBCPP_ASSERTION_SEMANTIC_IGNORE && \ - _LIBCPP_ASSERTION_SEMANTIC != _LIBCPP_ASSERTION_SEMANTIC_OBSERVE && \ - _LIBCPP_ASSERTION_SEMANTIC != _LIBCPP_ASSERTION_SEMANTIC_QUICK_ENFORCE && \ - _LIBCPP_ASSERTION_SEMANTIC != _LIBCPP_ASSERTION_SEMANTIC_ENFORCE -# error _LIBCPP_ASSERTION_SEMANTIC must be set to one of the following values: \ +#if _LIBCPP_ASSERTION_SEMANTIC != _LIBCPP_ASSERTION_SEMANTIC_IGNORE && \ + _LIBCPP_ASSERTION_SEMANTIC != _LIBCPP_ASSERTION_SEMANTIC_OBSERVE && \ + _LIBCPP_ASSERTION_SEMANTIC != _LIBCPP_ASSERTION_SEMANTIC_QUICK_ENFORCE && \ + _LIBCPP_ASSERTION_SEMANTIC != _LIBCPP_ASSERTION_SEMANTIC_ENFORCE +# error _LIBCPP_ASSERTION_SEMANTIC must be set to one of the following values: \ _LIBCPP_ASSERTION_SEMANTIC_IGNORE, \ _LIBCPP_ASSERTION_SEMANTIC_OBSERVE, \ _LIBCPP_ASSERTION_SEMANTIC_QUICK_ENFORCE, \ _LIBCPP_ASSERTION_SEMANTIC_ENFORCE -# endif +#endif -# endif // _LIBCPP___CONFIGURATION_HARDENING_H +#endif // _LIBCPP___CONFIGURATION_HARDENING_H From 520892673cc1d2bbe213533ee07c286a2aa4dc4e Mon Sep 17 00:00:00 2001 From: Konstantin Varlamov Date: Wed, 12 Nov 2025 18:05:47 -0800 Subject: [PATCH 04/11] - Add new tests to check that the choice of the assertion semantic is orthogonal to the selected hardening mode; - Tweak some checks in existing tests to rely on the assertion semantic rather than using the hardening mode as a proxy. --- .../assertion_semantic_incorrect_value.sh.cpp | 26 +++++++++++++++++ .../override_with_enforce_semantic.pass.cpp | 29 +++++++++++++++++++ .../override_with_ignore_semantic.pass.cpp | 25 ++++++++++++++++ .../override_with_observe_semantic.pass.cpp | 26 +++++++++++++++++ ...rride_with_quick_enforce_semantic.pass.cpp | 28 ++++++++++++++++++ .../test_check_assertion.pass.cpp | 10 +++---- 6 files changed, 139 insertions(+), 5 deletions(-) create mode 100644 libcxx/test/libcxx/assertions/semantics/assertion_semantic_incorrect_value.sh.cpp create mode 100644 libcxx/test/libcxx/assertions/semantics/override_with_enforce_semantic.pass.cpp create mode 100644 libcxx/test/libcxx/assertions/semantics/override_with_ignore_semantic.pass.cpp create mode 100644 libcxx/test/libcxx/assertions/semantics/override_with_observe_semantic.pass.cpp create mode 100644 libcxx/test/libcxx/assertions/semantics/override_with_quick_enforce_semantic.pass.cpp diff --git a/libcxx/test/libcxx/assertions/semantics/assertion_semantic_incorrect_value.sh.cpp b/libcxx/test/libcxx/assertions/semantics/assertion_semantic_incorrect_value.sh.cpp new file mode 100644 index 0000000000000..f96694b5206e5 --- /dev/null +++ b/libcxx/test/libcxx/assertions/semantics/assertion_semantic_incorrect_value.sh.cpp @@ -0,0 +1,26 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +// This test verifies that setting the assertion semantic to a value that's not part of the predefined constants +// triggers a compile-time error. + +// Modules build produces a different error ("Could not build module 'std'"). +// UNSUPPORTED: clang-modules-build +// REQUIRES: verify-support + +// Note that GCC doesn't support `-Wno-macro-redefined`. +// RUN: %{verify} -U_LIBCPP_ASSERTION_SEMANTIC -D_LIBCPP_ASSERTION_SEMANTIC=42 +// Make sure that common cases of misuse produce readable errors. We deliberately disallow setting the assertion +// semantic as if it were a boolean flag. +// RUN: %{verify} -U_LIBCPP_ASSERTION_SEMANTIC -D_LIBCPP_ASSERTION_SEMANTIC=0 +// RUN: %{verify} -U_LIBCPP_ASSERTION_SEMANTIC -D_LIBCPP_ASSERTION_SEMANTIC=1 +// RUN: %{verify} -U_LIBCPP_ASSERTION_SEMANTIC -D_LIBCPP_ASSERTION_SEMANTIC + +#include + +// expected-error@*:* {{_LIBCPP_ASSERTION_SEMANTIC must be set to one of the following values: _LIBCPP_ASSERTION_SEMANTIC_IGNORE, _LIBCPP_ASSERTION_SEMANTIC_OBSERVE, _LIBCPP_ASSERTION_SEMANTIC_QUICK_ENFORCE, _LIBCPP_ASSERTION_SEMANTIC_ENFORCE}} diff --git a/libcxx/test/libcxx/assertions/semantics/override_with_enforce_semantic.pass.cpp b/libcxx/test/libcxx/assertions/semantics/override_with_enforce_semantic.pass.cpp new file mode 100644 index 0000000000000..b1da2b0143ad0 --- /dev/null +++ b/libcxx/test/libcxx/assertions/semantics/override_with_enforce_semantic.pass.cpp @@ -0,0 +1,29 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +// This test ensures that we can override the assertion semantic used by any checked hardening mode with `enforce` (this +// is valid for the `debug` mode as well, though a no-op). + +// `check_assertion.h` is only available starting from C++11 and requires Unix headers and regex support. +// REQUIRES: has-unix-headers +// UNSUPPORTED: c++03, no-localization +// UNSUPPORTED: libcpp-hardening-mode=none +// The ability to set a custom abort message is required to compare the assertion message. +// XFAIL: availability-verbose_abort-missing +// ADDITIONAL_COMPILE_FLAGS: -U_LIBCPP_ASSERTION_SEMANTIC -D_LIBCPP_ASSERTION_SEMANTIC=_LIBCPP_ASSERTION_SEMANTIC_ENFORCE + +#include +#include "check_assertion.h" + +int main(int, char**) { + _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(true, "Should not fire"); + TEST_LIBCPP_ASSERT_FAILURE([] { _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(false, "Should fire and log a message"); }(), + "Should fire and log a message"); + + return 0; +} diff --git a/libcxx/test/libcxx/assertions/semantics/override_with_ignore_semantic.pass.cpp b/libcxx/test/libcxx/assertions/semantics/override_with_ignore_semantic.pass.cpp new file mode 100644 index 0000000000000..91962bad1bc0a --- /dev/null +++ b/libcxx/test/libcxx/assertions/semantics/override_with_ignore_semantic.pass.cpp @@ -0,0 +1,25 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +// This test ensures that we can override the assertion semantic used by any hardening mode with `ignore` (this is valid +// for the `none` mode as well, though a no-op). + +// `check_assertion.h` is only available starting from C++11 and requires Unix headers and regex support. +// REQUIRES: has-unix-headers +// UNSUPPORTED: c++03, no-localization +// ADDITIONAL_COMPILE_FLAGS: -U_LIBCPP_ASSERTION_SEMANTIC -D_LIBCPP_ASSERTION_SEMANTIC=_LIBCPP_ASSERTION_SEMANTIC_IGNORE + +#include +#include "check_assertion.h" + +int main(int, char**) { + _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(true, "Should not fire"); + _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(false, "Also should not fire"); + + return 0; +} diff --git a/libcxx/test/libcxx/assertions/semantics/override_with_observe_semantic.pass.cpp b/libcxx/test/libcxx/assertions/semantics/override_with_observe_semantic.pass.cpp new file mode 100644 index 0000000000000..6fa89d821197d --- /dev/null +++ b/libcxx/test/libcxx/assertions/semantics/override_with_observe_semantic.pass.cpp @@ -0,0 +1,26 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +// This test ensures that we can override the assertion semantic used by any checked hardening mode with `observe`. + +// `check_assertion.h` is only available starting from C++11 and requires Unix headers and regex support. +// REQUIRES: has-unix-headers +// UNSUPPORTED: c++03, no-localization +// UNSUPPORTED: libcpp-hardening-mode=none +// ADDITIONAL_COMPILE_FLAGS: -U_LIBCPP_ASSERTION_SEMANTIC -D_LIBCPP_ASSERTION_SEMANTIC=_LIBCPP_ASSERTION_SEMANTIC_OBSERVE + +#include +#include "check_assertion.h" + +int main(int, char**) { + _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(true, "Should not fire"); + _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(false, "Also should not fire"); + // TODO(hardening): check that a message is logged. + + return 0; +} diff --git a/libcxx/test/libcxx/assertions/semantics/override_with_quick_enforce_semantic.pass.cpp b/libcxx/test/libcxx/assertions/semantics/override_with_quick_enforce_semantic.pass.cpp new file mode 100644 index 0000000000000..4229e6a55966a --- /dev/null +++ b/libcxx/test/libcxx/assertions/semantics/override_with_quick_enforce_semantic.pass.cpp @@ -0,0 +1,28 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +// This test ensures that we can override the assertion semantic used by any checked hardening mode with `quick-enforce` +// (this is valid for the `fast` and `extensive` modes as well, though a no-op). + +// `check_assertion.h` is only available starting from C++11 and requires Unix headers and regex support. +// REQUIRES: has-unix-headers +// UNSUPPORTED: c++03, no-localization +// UNSUPPORTED: libcpp-hardening-mode=none +// ADDITIONAL_COMPILE_FLAGS: -U_LIBCPP_ASSERTION_SEMANTIC -D_LIBCPP_ASSERTION_SEMANTIC=_LIBCPP_ASSERTION_SEMANTIC_QUICK_ENFORCE + +#include +#include "check_assertion.h" + +int main(int, char**) { + _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(true, "Should not fire"); + TEST_LIBCPP_ASSERT_FAILURE([] { _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(false, "Should fire without logging a message"); }(), + "The message should not matter"); + + return 0; +} + diff --git a/libcxx/test/support/test.support/test_check_assertion.pass.cpp b/libcxx/test/support/test.support/test_check_assertion.pass.cpp index 78e47b32cdd2b..2ac7caa2fd90e 100644 --- a/libcxx/test/support/test.support/test_check_assertion.pass.cpp +++ b/libcxx/test/support/test.support/test_check_assertion.pass.cpp @@ -21,11 +21,11 @@ template bool TestDeathTest( Outcome expected_outcome, DeathCause expected_cause, const char* stmt, Func&& func, const Matcher& matcher) { auto get_matcher = [&] { -#if _LIBCPP_HARDENING_MODE == _LIBCPP_HARDENING_MODE_DEBUG - return matcher; -#else +#if _LIBCPP_ASSERTION_SEMANTIC == _LIBCPP_ASSERTION_SEMANTIC_QUICK_ENFORCE (void)matcher; return MakeAnyMatcher(); +#else + return matcher; #endif }; @@ -69,7 +69,7 @@ bool TestDeathTest( // clang-format on -#if _LIBCPP_HARDENING_MODE == _LIBCPP_HARDENING_MODE_DEBUG +#if _LIBCPP_ASSERTION_SEMANTIC == _LIBCPP_ASSERTION_SEMANTIC_ENFORCE DeathCause assertion_death_cause = DeathCause::VerboseAbort; #else DeathCause assertion_death_cause = DeathCause::Trap; @@ -99,7 +99,7 @@ int main(int, char**) { // Success -- assertion failure with a specific matcher. TEST_DEATH_TEST_MATCHES(Outcome::Success, assertion_death_cause, good_matcher, fail_assert()); -# if _LIBCPP_HARDENING_MODE == _LIBCPP_HARDENING_MODE_DEBUG +#if _LIBCPP_ASSERTION_SEMANTIC == _LIBCPP_ASSERTION_SEMANTIC_ENFORCE // Failure -- error message doesn't match. TEST_DEATH_TEST_MATCHES(Outcome::UnexpectedErrorMessage, assertion_death_cause, bad_matcher, fail_assert()); # endif From b0f817460dc282b88c457d9d022323b223b4502f Mon Sep 17 00:00:00 2001 From: Konstantin Varlamov Date: Wed, 12 Nov 2025 18:07:40 -0800 Subject: [PATCH 05/11] Make `hardening_dependent` a special value for choosing the assertion semantic (rather than relying on it being not set). --- libcxx/CMakeLists.txt | 24 +++++----- libcxx/include/__configuration/hardening.h | 52 +++++++++++++--------- 2 files changed, 45 insertions(+), 31 deletions(-) diff --git a/libcxx/CMakeLists.txt b/libcxx/CMakeLists.txt index bebef101fcdff..1423b6713fd35 100644 --- a/libcxx/CMakeLists.txt +++ b/libcxx/CMakeLists.txt @@ -66,16 +66,16 @@ if (NOT "${LIBCXX_HARDENING_MODE}" IN_LIST LIBCXX_SUPPORTED_HARDENING_MODES) message(FATAL_ERROR "Unsupported hardening mode: '${LIBCXX_HARDENING_MODE}'. Supported values are ${LIBCXX_SUPPORTED_HARDENING_MODES}.") endif() -set(LIBCXX_SUPPORTED_ASSERTION_SEMANTICS ignore observe quick_enforce enforce) -set(LIBCXX_ASSERTION_SEMANTIC "" CACHE STRING +set(LIBCXX_SUPPORTED_ASSERTION_SEMANTICS hardening_dependent ignore observe quick_enforce enforce) +set(LIBCXX_ASSERTION_SEMANTIC "hardening_dependent" CACHE STRING "Specify the default assertion semantic to use. This semantic will be used inside the compiled library and will be the default when compiling user code. - If not defined, the library will select the assertion semantic based on the hardening - mode in effect. Note that users can override this setting in their own code. - This does not affect the ABI. Supported values are - ${LIBCXX_SUPPORTED_ASSERTION_SEMANTICS}.") + Note that users can override this setting in their own code. This does not + affect the ABI. Supported values are ${LIBCXX_SUPPORTED_ASSERTION_SEMANTICS}. + `hardening_dependent` is a special value that instructs the library to select + the assertion semantic based on the hardening mode in effect.") -if (NOT "${LIBCXX_ASSERTION_SEMANTIC}" STREQUAL "" AND NOT "${LIBCXX_ASSERTION_SEMANTIC}" IN_LIST LIBCXX_SUPPORTED_ASSERTION_SEMANTICS) +if (NOT "${LIBCXX_ASSERTION_SEMANTIC}" IN_LIST LIBCXX_SUPPORTED_ASSERTION_SEMANTICS) message(FATAL_ERROR "Unsupported assertion semantic: '${LIBCXX_ASSERTION_SEMANTIC}'. Supported values are ${LIBCXX_SUPPORTED_ASSERTION_SEMANTICS}.") endif() @@ -776,14 +776,16 @@ elseif (LIBCXX_HARDENING_MODE STREQUAL "extensive") elseif (LIBCXX_HARDENING_MODE STREQUAL "debug") config_define(8 _LIBCPP_HARDENING_MODE_DEFAULT) endif() -if (LIBCXX_ASSERTION_SEMANTIC STREQUAL "ignore") +if (LIBCXX_ASSERTION_SEMANTIC STREQUAL "hardening_dependent") config_define(2 _LIBCPP_ASSERTION_SEMANTIC_DEFAULT) -elseif (LIBCXX_ASSERTION_SEMANTIC STREQUAL "observe") +elseif (LIBCXX_ASSERTION_SEMANTIC STREQUAL "ignore") config_define(4 _LIBCPP_ASSERTION_SEMANTIC_DEFAULT) -elseif (LIBCXX_ASSERTION_SEMANTIC STREQUAL "quick_enforce") +elseif (LIBCXX_ASSERTION_SEMANTIC STREQUAL "observe") config_define(8 _LIBCPP_ASSERTION_SEMANTIC_DEFAULT) -elseif (LIBCXX_ASSERTION_SEMANTIC STREQUAL "enforce") +elseif (LIBCXX_ASSERTION_SEMANTIC STREQUAL "quick_enforce") config_define(16 _LIBCPP_ASSERTION_SEMANTIC_DEFAULT) +elseif (LIBCXX_ASSERTION_SEMANTIC STREQUAL "enforce") + config_define(32 _LIBCPP_ASSERTION_SEMANTIC_DEFAULT) endif() if (LIBCXX_PSTL_BACKEND STREQUAL "serial") diff --git a/libcxx/include/__configuration/hardening.h b/libcxx/include/__configuration/hardening.h index c761d36232452..7c350fa30eca3 100644 --- a/libcxx/include/__configuration/hardening.h +++ b/libcxx/include/__configuration/hardening.h @@ -135,13 +135,25 @@ _LIBCPP_HARDENING_MODE_EXTENSIVE, \ _LIBCPP_HARDENING_MODE_DEBUG #endif -// Hardening assertion semantics generally mirror the evaluation semantics of C++26 Contracts: +// The library provides the macro `_LIBCPP_ASSERTION_SEMANTIC` for configuring the assertion semantic used by hardening; +// it can be set to one of the following values: +// +// - `_LIBCPP_ASSERTION_SEMANTIC_IGNORE`; +// - `_LIBCPP_ASSERTION_SEMANTIC_OBSERVE`; +// - `_LIBCPP_ASSERTION_SEMANTIC_QUICK_ENFORCE`; +// - `_LIBCPP_ASSERTION_SEMANTIC_ENFORCE`. +// +// libc++ 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. // +// Additionally, a special `hardening-dependent` value selects the assertion semantic based on the hardening mode in +// effect: the production-capable modes (`fast` and `extensive`) map to `quick_enforce` and the `debug` mode maps to +// `enforce`. +// // 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; @@ -150,42 +162,42 @@ _LIBCPP_HARDENING_MODE_DEBUG // 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) +# define _LIBCPP_ASSERTION_SEMANTIC_HARDENING_DEPENDENT (1 << 1) +# define _LIBCPP_ASSERTION_SEMANTIC_IGNORE (1 << 2) +# define _LIBCPP_ASSERTION_SEMANTIC_OBSERVE (1 << 3) +# define _LIBCPP_ASSERTION_SEMANTIC_QUICK_ENFORCE (1 << 4) +# define _LIBCPP_ASSERTION_SEMANTIC_ENFORCE (1 << 5) // clang-format on -// If the user or the vendor attempt to configure the assertion semantic, check that it is allowed in the current -// environment. -#if defined(_LIBCPP_ASSERTION_SEMANTIC) || defined(_LIBCPP_ASSERTION_SEMANTIC_DEFAULT) +// If the user attempts to configure the assertion semantic, check that it is allowed in the current environment. +#if defined(_LIBCPP_ASSERTION_SEMANTIC) # 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 // defined(_LIBCPP_ASSERTION_SEMANTIC) || defined(_LIBCPP_ASSERTION_SEMANTIC_DEFAULT) +#endif // defined(_LIBCPP_ASSERTION_SEMANTIC) -// There are 2 ways to configure the assertion semantic, listed in order of precedence: -// 1. The `_LIBCPP_ASSERTION_SEMANTIC` macro, defined directly by the user. -// 2. The `LIBCXX_ASSERTION_SEMANTIC` CMake variable, set by the vendor. -// If neither `_LIBCPP_ASSERTION_SEMANTIC` nor `LIBCXX_ASSERTION_SEMANTIC` are defined, the default mapping is used -// which determines the semantic based on the hardening mode in effect: production-capable modes map to `quick-enforce` -// (i.e., trap) and the `debug` mode maps to `enforce` (i.e., log and abort). -#ifndef _LIBCPP_ASSERTION_SEMANTIC // User-provided semantic takes top priority -- don't override if set. +// User-provided semantic takes top priority -- don't override if set. +#ifndef _LIBCPP_ASSERTION_SEMANTIC + +# ifndef _LIBCPP_ASSERTION_SEMANTIC_DEFAULT +# error _LIBCPP_ASSERTION_SEMANTIC_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 -# ifdef _LIBCPP_ASSERTION_SEMANTIC_DEFAULT // Vendor-provided semantic takes second priority. +# if _LIBCPP_ASSERTION_SEMANTIC_DEFAULT != _LIBCPP_ASSERTION_SEMANTIC_HARDENING_DEPENDENT # define _LIBCPP_ASSERTION_SEMANTIC _LIBCPP_ASSERTION_SEMANTIC_DEFAULT -# else // Fallback: use the default mapping. +# else # 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 -# endif // ifdef _LIBCPP_ASSERTION_SEMANTIC_DEFAULT +# endif // _LIBCPP_ASSERTION_SEMANTIC_DEFAULT != _LIBCPP_ASSERTION_SEMANTIC_HARDENING_DEPENDENT -#endif // _LIBCPP_ASSERTION_SEMANTIC +#endif // #ifndef _LIBCPP_ASSERTION_SEMANTIC // Finally, validate the selected semantic (in case the user tries setting it to an incorrect value): #if _LIBCPP_ASSERTION_SEMANTIC != _LIBCPP_ASSERTION_SEMANTIC_IGNORE && \ From 096249d04cf0a2e2adc84b6d0ec6b6bd6f7d2316 Mon Sep 17 00:00:00 2001 From: Konstantin Varlamov Date: Thu, 13 Nov 2025 00:37:19 -0800 Subject: [PATCH 06/11] CI fixes (formatting, disable semantic-related tests in the C++03 mode) --- .../semantics/assertion_semantic_incorrect_value.sh.cpp | 1 + .../semantics/override_with_quick_enforce_semantic.pass.cpp | 5 +++-- .../test/support/test.support/test_check_assertion.pass.cpp | 2 +- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/libcxx/test/libcxx/assertions/semantics/assertion_semantic_incorrect_value.sh.cpp b/libcxx/test/libcxx/assertions/semantics/assertion_semantic_incorrect_value.sh.cpp index f96694b5206e5..310a2e70712d1 100644 --- a/libcxx/test/libcxx/assertions/semantics/assertion_semantic_incorrect_value.sh.cpp +++ b/libcxx/test/libcxx/assertions/semantics/assertion_semantic_incorrect_value.sh.cpp @@ -11,6 +11,7 @@ // Modules build produces a different error ("Could not build module 'std'"). // UNSUPPORTED: clang-modules-build +// UNSUPPORTED: c++03 // REQUIRES: verify-support // Note that GCC doesn't support `-Wno-macro-redefined`. diff --git a/libcxx/test/libcxx/assertions/semantics/override_with_quick_enforce_semantic.pass.cpp b/libcxx/test/libcxx/assertions/semantics/override_with_quick_enforce_semantic.pass.cpp index 4229e6a55966a..950f46cc9600d 100644 --- a/libcxx/test/libcxx/assertions/semantics/override_with_quick_enforce_semantic.pass.cpp +++ b/libcxx/test/libcxx/assertions/semantics/override_with_quick_enforce_semantic.pass.cpp @@ -20,8 +20,9 @@ int main(int, char**) { _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(true, "Should not fire"); - TEST_LIBCPP_ASSERT_FAILURE([] { _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(false, "Should fire without logging a message"); }(), - "The message should not matter"); + TEST_LIBCPP_ASSERT_FAILURE( + [] { _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(false, "Should fire without logging a message"); }(), + "The message should not matter"); return 0; } diff --git a/libcxx/test/support/test.support/test_check_assertion.pass.cpp b/libcxx/test/support/test.support/test_check_assertion.pass.cpp index 2ac7caa2fd90e..9d356ef30a501 100644 --- a/libcxx/test/support/test.support/test_check_assertion.pass.cpp +++ b/libcxx/test/support/test.support/test_check_assertion.pass.cpp @@ -99,7 +99,7 @@ int main(int, char**) { // Success -- assertion failure with a specific matcher. TEST_DEATH_TEST_MATCHES(Outcome::Success, assertion_death_cause, good_matcher, fail_assert()); -#if _LIBCPP_ASSERTION_SEMANTIC == _LIBCPP_ASSERTION_SEMANTIC_ENFORCE +# if _LIBCPP_ASSERTION_SEMANTIC == _LIBCPP_ASSERTION_SEMANTIC_ENFORCE // Failure -- error message doesn't match. TEST_DEATH_TEST_MATCHES(Outcome::UnexpectedErrorMessage, assertion_death_cause, bad_matcher, fail_assert()); # endif From 9b0daf4b51b65b62c4be7c10e447ee6ad0b0e9e9 Mon Sep 17 00:00:00 2001 From: Konstantin Varlamov Date: Thu, 13 Nov 2025 01:53:56 -0800 Subject: [PATCH 07/11] Fix CI (formatting, make semantics tests require experimental) --- .../semantics/assertion_semantic_incorrect_value.sh.cpp | 2 +- .../semantics/override_with_enforce_semantic.pass.cpp | 2 +- .../semantics/override_with_ignore_semantic.pass.cpp | 1 + .../semantics/override_with_observe_semantic.pass.cpp | 2 +- .../semantics/override_with_quick_enforce_semantic.pass.cpp | 3 +-- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/libcxx/test/libcxx/assertions/semantics/assertion_semantic_incorrect_value.sh.cpp b/libcxx/test/libcxx/assertions/semantics/assertion_semantic_incorrect_value.sh.cpp index 310a2e70712d1..a7a8a02b5358b 100644 --- a/libcxx/test/libcxx/assertions/semantics/assertion_semantic_incorrect_value.sh.cpp +++ b/libcxx/test/libcxx/assertions/semantics/assertion_semantic_incorrect_value.sh.cpp @@ -11,7 +11,7 @@ // Modules build produces a different error ("Could not build module 'std'"). // UNSUPPORTED: clang-modules-build -// UNSUPPORTED: c++03 +// UNSUPPORTED: c++03, libcpp-has-no-experimental-hardening-observe-semantic // REQUIRES: verify-support // Note that GCC doesn't support `-Wno-macro-redefined`. diff --git a/libcxx/test/libcxx/assertions/semantics/override_with_enforce_semantic.pass.cpp b/libcxx/test/libcxx/assertions/semantics/override_with_enforce_semantic.pass.cpp index b1da2b0143ad0..97444f0258a3a 100644 --- a/libcxx/test/libcxx/assertions/semantics/override_with_enforce_semantic.pass.cpp +++ b/libcxx/test/libcxx/assertions/semantics/override_with_enforce_semantic.pass.cpp @@ -12,7 +12,7 @@ // `check_assertion.h` is only available starting from C++11 and requires Unix headers and regex support. // REQUIRES: has-unix-headers // UNSUPPORTED: c++03, no-localization -// UNSUPPORTED: libcpp-hardening-mode=none +// UNSUPPORTED: libcpp-hardening-mode=none, libcpp-has-no-experimental-hardening-observe-semantic // The ability to set a custom abort message is required to compare the assertion message. // XFAIL: availability-verbose_abort-missing // ADDITIONAL_COMPILE_FLAGS: -U_LIBCPP_ASSERTION_SEMANTIC -D_LIBCPP_ASSERTION_SEMANTIC=_LIBCPP_ASSERTION_SEMANTIC_ENFORCE diff --git a/libcxx/test/libcxx/assertions/semantics/override_with_ignore_semantic.pass.cpp b/libcxx/test/libcxx/assertions/semantics/override_with_ignore_semantic.pass.cpp index 91962bad1bc0a..2658a32f2cb30 100644 --- a/libcxx/test/libcxx/assertions/semantics/override_with_ignore_semantic.pass.cpp +++ b/libcxx/test/libcxx/assertions/semantics/override_with_ignore_semantic.pass.cpp @@ -12,6 +12,7 @@ // `check_assertion.h` is only available starting from C++11 and requires Unix headers and regex support. // REQUIRES: has-unix-headers // UNSUPPORTED: c++03, no-localization +// UNSUPPORTED: libcpp-has-no-experimental-hardening-observe-semantic // ADDITIONAL_COMPILE_FLAGS: -U_LIBCPP_ASSERTION_SEMANTIC -D_LIBCPP_ASSERTION_SEMANTIC=_LIBCPP_ASSERTION_SEMANTIC_IGNORE #include diff --git a/libcxx/test/libcxx/assertions/semantics/override_with_observe_semantic.pass.cpp b/libcxx/test/libcxx/assertions/semantics/override_with_observe_semantic.pass.cpp index 6fa89d821197d..2a73f8b0a3616 100644 --- a/libcxx/test/libcxx/assertions/semantics/override_with_observe_semantic.pass.cpp +++ b/libcxx/test/libcxx/assertions/semantics/override_with_observe_semantic.pass.cpp @@ -11,7 +11,7 @@ // `check_assertion.h` is only available starting from C++11 and requires Unix headers and regex support. // REQUIRES: has-unix-headers // UNSUPPORTED: c++03, no-localization -// UNSUPPORTED: libcpp-hardening-mode=none +// UNSUPPORTED: libcpp-hardening-mode=none, libcpp-has-no-experimental-hardening-observe-semantic // ADDITIONAL_COMPILE_FLAGS: -U_LIBCPP_ASSERTION_SEMANTIC -D_LIBCPP_ASSERTION_SEMANTIC=_LIBCPP_ASSERTION_SEMANTIC_OBSERVE #include diff --git a/libcxx/test/libcxx/assertions/semantics/override_with_quick_enforce_semantic.pass.cpp b/libcxx/test/libcxx/assertions/semantics/override_with_quick_enforce_semantic.pass.cpp index 950f46cc9600d..3448fb3afc1ea 100644 --- a/libcxx/test/libcxx/assertions/semantics/override_with_quick_enforce_semantic.pass.cpp +++ b/libcxx/test/libcxx/assertions/semantics/override_with_quick_enforce_semantic.pass.cpp @@ -12,7 +12,7 @@ // `check_assertion.h` is only available starting from C++11 and requires Unix headers and regex support. // REQUIRES: has-unix-headers // UNSUPPORTED: c++03, no-localization -// UNSUPPORTED: libcpp-hardening-mode=none +// UNSUPPORTED: libcpp-hardening-mode=none, libcpp-has-no-experimental-hardening-observe-semantic // ADDITIONAL_COMPILE_FLAGS: -U_LIBCPP_ASSERTION_SEMANTIC -D_LIBCPP_ASSERTION_SEMANTIC=_LIBCPP_ASSERTION_SEMANTIC_QUICK_ENFORCE #include @@ -26,4 +26,3 @@ int main(int, char**) { return 0; } - From f613fde33f0f23dd387eaf463a53ad226b65b8a5 Mon Sep 17 00:00:00 2001 From: Konstantin Varlamov Date: Thu, 13 Nov 2025 11:56:57 -0800 Subject: [PATCH 08/11] - Reflect the assertion semantic in the library ABI tag (with a test); - Address other feedback. --- libcxx/include/__config | 14 +++- libcxx/include/__configuration/hardening.h | 3 +- .../odr_signature.assertion_semantics.sh.cpp | 71 +++++++++++++++++++ .../assertion_semantic_incorrect_value.sh.cpp | 4 +- .../override_with_enforce_semantic.pass.cpp | 4 +- .../override_with_ignore_semantic.pass.cpp | 4 +- .../override_with_observe_semantic.pass.cpp | 3 +- ...rride_with_quick_enforce_semantic.pass.cpp | 2 +- 8 files changed, 96 insertions(+), 9 deletions(-) create mode 100644 libcxx/test/extensions/libcxx/odr_signature.assertion_semantics.sh.cpp diff --git a/libcxx/include/__config b/libcxx/include/__config index e907961446201..d45f101861e2d 100644 --- a/libcxx/include/__config +++ b/libcxx/include/__config @@ -291,6 +291,16 @@ typedef __char32_t char32_t; # define _LIBCPP_HARDENING_SIG n // "none" # endif +# if _LIBCPP_ASSERTION_SEMANTIC == _LIBCPP_ASSERTION_SEMANTIC_OBSERVE +# define _LIBCPP_ASSERTION_SEMANTIC_SIG o +# elif _LIBCPP_ASSERTION_SEMANTIC == _LIBCPP_ASSERTION_SEMANTIC_QUICK_ENFORCE +# define _LIBCPP_ASSERTION_SEMANTIC_SIG q +# elif _LIBCPP_ASSERTION_SEMANTIC == _LIBCPP_ASSERTION_SEMANTIC_ENFORCE +# define _LIBCPP_ASSERTION_SEMANTIC_SIG e +# else +# define _LIBCPP_ASSERTION_SEMANTIC_SIG i // `ignore` +# endif + # if !_LIBCPP_HAS_EXCEPTIONS # define _LIBCPP_EXCEPTIONS_SIG n # else @@ -298,7 +308,9 @@ typedef __char32_t char32_t; # endif # define _LIBCPP_ODR_SIGNATURE \ - _LIBCPP_CONCAT(_LIBCPP_CONCAT(_LIBCPP_HARDENING_SIG, _LIBCPP_EXCEPTIONS_SIG), _LIBCPP_VERSION) + _LIBCPP_CONCAT( \ + _LIBCPP_CONCAT(_LIBCPP_CONCAT(_LIBCPP_HARDENING_SIG, _LIBCPP_ASSERTION_SEMANTIC_SIG), _LIBCPP_EXCEPTIONS_SIG), \ + _LIBCPP_VERSION) // This macro marks a symbol as being hidden from libc++'s ABI. This is achieved // on two levels: diff --git a/libcxx/include/__configuration/hardening.h b/libcxx/include/__configuration/hardening.h index 7c350fa30eca3..5723f5a65e1bf 100644 --- a/libcxx/include/__configuration/hardening.h +++ b/libcxx/include/__configuration/hardening.h @@ -152,7 +152,8 @@ _LIBCPP_HARDENING_MODE_DEBUG // // Additionally, a special `hardening-dependent` value selects the assertion semantic based on the hardening mode in // effect: the production-capable modes (`fast` and `extensive`) map to `quick_enforce` and the `debug` mode maps to -// `enforce`. +// `enforce`. The `hardening-dependent` semantic cannot be selected explicitly, it is only used when no assertion +// semantic is provided by the user _and_ the library's default semantic is configured to be dependent on hardening. // // Notes: // - Continuing execution after a hardening check fails results in undefined behavior; the `observe` semantic is meant diff --git a/libcxx/test/extensions/libcxx/odr_signature.assertion_semantics.sh.cpp b/libcxx/test/extensions/libcxx/odr_signature.assertion_semantics.sh.cpp new file mode 100644 index 0000000000000..a352cab8fd007 --- /dev/null +++ b/libcxx/test/extensions/libcxx/odr_signature.assertion_semantics.sh.cpp @@ -0,0 +1,71 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +// ABI tags have no effect in MSVC mode. +// XFAIL: msvc + +// XFAIL: FROZEN-CXX03-HEADERS-FIXME + +// Test that we encode the assertion semantic in an ABI tag to avoid ODR violations when linking TUs that have different +// values for it. + +// Note that GCC doesn't support `-Wno-macro-redefined`. +// RUN: %{cxx} %s %{flags} %{compile_flags} -c -DTU1 -U_LIBCPP_ASSERTION_SEMANTIC -D_LIBCPP_ASSERTION_SEMANTIC=_LIBCPP_ASSERTION_SEMANTIC_IGNORE -o %t.tu1.o +// RUN: %{cxx} %s %{flags} %{compile_flags} -c -DTU2 -U_LIBCPP_ASSERTION_SEMANTIC -D_LIBCPP_ASSERTION_SEMANTIC=_LIBCPP_ASSERTION_SEMANTIC_OBSERVE -o %t.tu2.o +// RUN: %{cxx} %s %{flags} %{compile_flags} -c -DTU3 -U_LIBCPP_ASSERTION_SEMANTIC -D_LIBCPP_ASSERTION_SEMANTIC=_LIBCPP_ASSERTION_SEMANTIC_QUICK_ENFORCE -o %t.tu3.o +// RUN: %{cxx} %s %{flags} %{compile_flags} -c -DTU4 -U_LIBCPP_ASSERTION_SEMANTIC -D_LIBCPP_ASSERTION_SEMANTIC=_LIBCPP_ASSERTION_SEMANTIC_ENFORCE -o %t.tu4.o +// RUN: %{cxx} %s %{flags} %{compile_flags} -c -DMAIN -o %t.main.o +// RUN: %{cxx} %t.tu1.o %t.tu2.o %t.tu3.o %t.tu4.o %t.main.o %{flags} %{link_flags} -o %t.exe +// RUN: %{exec} %t.exe + +#include "test_macros.h" + +// `ignore` assertion semantic. +#ifdef TU1 +# include <__config> +_LIBCPP_HIDE_FROM_ABI TEST_NOINLINE inline int f() { return 1; } +int tu1() { return f(); } +#endif // TU1 + +// `observe` assertion semantic. +#ifdef TU2 +# include <__config> +_LIBCPP_HIDE_FROM_ABI TEST_NOINLINE inline int f() { return 2; } +int tu2() { return f(); } +#endif // TU2 + +// `quick-enforce` assertion semantic. +#ifdef TU3 +# include <__config> +_LIBCPP_HIDE_FROM_ABI TEST_NOINLINE inline int f() { return 3; } +int tu3() { return f(); } +#endif // TU3 + +// `enforce` assertion semantic. +#ifdef TU4 +# include <__config> +_LIBCPP_HIDE_FROM_ABI TEST_NOINLINE inline int f() { return 4; } +int tu4() { return f(); } +#endif // TU4 + +#ifdef MAIN +# include + +int tu1(); +int tu2(); +int tu3(); +int tu4(); + +int main(int, char**) { + assert(tu1() == 1); + assert(tu2() == 2); + assert(tu3() == 3); + assert(tu4() == 4); + return 0; +} +#endif // MAIN diff --git a/libcxx/test/libcxx/assertions/semantics/assertion_semantic_incorrect_value.sh.cpp b/libcxx/test/libcxx/assertions/semantics/assertion_semantic_incorrect_value.sh.cpp index a7a8a02b5358b..d7c1e26491ba9 100644 --- a/libcxx/test/libcxx/assertions/semantics/assertion_semantic_incorrect_value.sh.cpp +++ b/libcxx/test/libcxx/assertions/semantics/assertion_semantic_incorrect_value.sh.cpp @@ -14,8 +14,10 @@ // UNSUPPORTED: c++03, libcpp-has-no-experimental-hardening-observe-semantic // REQUIRES: verify-support -// Note that GCC doesn't support `-Wno-macro-redefined`. // RUN: %{verify} -U_LIBCPP_ASSERTION_SEMANTIC -D_LIBCPP_ASSERTION_SEMANTIC=42 +// `hardening-dependent` cannot be set as the semantic (it's only an indicator to use hardening-related logic to pick +// the final semantic). +// RUN: %{verify} -U_LIBCPP_ASSERTION_SEMANTIC -D_LIBCPP_ASSERTION_SEMANTIC=_LIBCPP_ASSERTION_SEMANTIC_HARDENING_DEPENDENT // Make sure that common cases of misuse produce readable errors. We deliberately disallow setting the assertion // semantic as if it were a boolean flag. // RUN: %{verify} -U_LIBCPP_ASSERTION_SEMANTIC -D_LIBCPP_ASSERTION_SEMANTIC=0 diff --git a/libcxx/test/libcxx/assertions/semantics/override_with_enforce_semantic.pass.cpp b/libcxx/test/libcxx/assertions/semantics/override_with_enforce_semantic.pass.cpp index 97444f0258a3a..056864e1aea71 100644 --- a/libcxx/test/libcxx/assertions/semantics/override_with_enforce_semantic.pass.cpp +++ b/libcxx/test/libcxx/assertions/semantics/override_with_enforce_semantic.pass.cpp @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -// This test ensures that we can override the assertion semantic used by any checked hardening mode with `enforce` (this -// is valid for the `debug` mode as well, though a no-op). +// This test ensures that we can override the assertion semantic used by any checked hardening mode with `enforce` on +// a per-TU basis (this is valid for the `debug` mode as well, though a no-op). // `check_assertion.h` is only available starting from C++11 and requires Unix headers and regex support. // REQUIRES: has-unix-headers diff --git a/libcxx/test/libcxx/assertions/semantics/override_with_ignore_semantic.pass.cpp b/libcxx/test/libcxx/assertions/semantics/override_with_ignore_semantic.pass.cpp index 2658a32f2cb30..b8c9028fe2e5c 100644 --- a/libcxx/test/libcxx/assertions/semantics/override_with_ignore_semantic.pass.cpp +++ b/libcxx/test/libcxx/assertions/semantics/override_with_ignore_semantic.pass.cpp @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -// This test ensures that we can override the assertion semantic used by any hardening mode with `ignore` (this is valid -// for the `none` mode as well, though a no-op). +// This test ensures that we can override the assertion semantic used by any hardening mode with `ignore` on a per-TU +// basis (this is valid for the `none` mode as well, though a no-op). // `check_assertion.h` is only available starting from C++11 and requires Unix headers and regex support. // REQUIRES: has-unix-headers diff --git a/libcxx/test/libcxx/assertions/semantics/override_with_observe_semantic.pass.cpp b/libcxx/test/libcxx/assertions/semantics/override_with_observe_semantic.pass.cpp index 2a73f8b0a3616..a14c44f5a8e73 100644 --- a/libcxx/test/libcxx/assertions/semantics/override_with_observe_semantic.pass.cpp +++ b/libcxx/test/libcxx/assertions/semantics/override_with_observe_semantic.pass.cpp @@ -6,7 +6,8 @@ // //===----------------------------------------------------------------------===// -// This test ensures that we can override the assertion semantic used by any checked hardening mode with `observe`. +// This test ensures that we can override the assertion semantic used by any checked hardening mode with `observe` on +// a per-TU basis. // `check_assertion.h` is only available starting from C++11 and requires Unix headers and regex support. // REQUIRES: has-unix-headers diff --git a/libcxx/test/libcxx/assertions/semantics/override_with_quick_enforce_semantic.pass.cpp b/libcxx/test/libcxx/assertions/semantics/override_with_quick_enforce_semantic.pass.cpp index 3448fb3afc1ea..be5038c4bb4ff 100644 --- a/libcxx/test/libcxx/assertions/semantics/override_with_quick_enforce_semantic.pass.cpp +++ b/libcxx/test/libcxx/assertions/semantics/override_with_quick_enforce_semantic.pass.cpp @@ -7,7 +7,7 @@ //===----------------------------------------------------------------------===// // This test ensures that we can override the assertion semantic used by any checked hardening mode with `quick-enforce` -// (this is valid for the `fast` and `extensive` modes as well, though a no-op). +// on a per-TU basis (this is valid for the `fast` and `extensive` modes as well, though a no-op). // `check_assertion.h` is only available starting from C++11 and requires Unix headers and regex support. // REQUIRES: has-unix-headers From ae0a272edf3ac3ae700d8d0ccf91646c760873a1 Mon Sep 17 00:00:00 2001 From: Konstantin Varlamov Date: Thu, 13 Nov 2025 16:55:10 -0800 Subject: [PATCH 09/11] Address feedback: update documentation, marka test unsupported in C++03. --- libcxx/docs/Hardening.rst | 21 +++++++++++++++++++ .../odr_signature.assertion_semantics.sh.cpp | 4 ++-- 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/libcxx/docs/Hardening.rst b/libcxx/docs/Hardening.rst index 1cdb3605c38ab..1360518379aef 100644 --- a/libcxx/docs/Hardening.rst +++ b/libcxx/docs/Hardening.rst @@ -328,6 +328,20 @@ following options to the compiler: All the :ref:`same notes ` apply to setting this macro as for setting ``_LIBCPP_HARDENING_MODE``. +Notes for vendors +----------------- + +Similarly to hardening modes, vendors can set the default assertion semantic by +providing ``LIBCXX_ASSERTION_SEMANTIC`` as a configuration option, with the +possible values of ``hardening_dependent``, ``ignore``, ``observe``, +``quick_enforce`` and ``enforce``. The default value is ``hardening_dependent`` +which is a special value that instructs the library to select the semantic based +on the hardening mode in effect (the mapping is described in +:ref:`the main section on assertion semantics `). + +This option controls both the assertion semantic that the precompiled library is +built with and the default assertion semantic that users will build with. + .. _override-assertion-handler: Overriding the assertion failure handler @@ -447,6 +461,13 @@ The first character of an ABI tag encodes the hardening mode: - ``d`` -- [d]ebug mode; - ``n`` -- [n]one mode. +The second character of an ABI tag encodes the assertion semantic: + +- ``i`` -- [i]gnore semantic; +- ``o`` -- [o]bserve semantic; +- ``q`` -- [q]uick-enforce semantic; +- ``e`` -- [e]nforce semantic. + Hardened containers status ========================== diff --git a/libcxx/test/extensions/libcxx/odr_signature.assertion_semantics.sh.cpp b/libcxx/test/extensions/libcxx/odr_signature.assertion_semantics.sh.cpp index a352cab8fd007..cf4f682d296ab 100644 --- a/libcxx/test/extensions/libcxx/odr_signature.assertion_semantics.sh.cpp +++ b/libcxx/test/extensions/libcxx/odr_signature.assertion_semantics.sh.cpp @@ -9,12 +9,12 @@ // ABI tags have no effect in MSVC mode. // XFAIL: msvc -// XFAIL: FROZEN-CXX03-HEADERS-FIXME +// Assertion semantics are not supported in C++03 mode +// UNSUPPORTED: std=c++03 // Test that we encode the assertion semantic in an ABI tag to avoid ODR violations when linking TUs that have different // values for it. -// Note that GCC doesn't support `-Wno-macro-redefined`. // RUN: %{cxx} %s %{flags} %{compile_flags} -c -DTU1 -U_LIBCPP_ASSERTION_SEMANTIC -D_LIBCPP_ASSERTION_SEMANTIC=_LIBCPP_ASSERTION_SEMANTIC_IGNORE -o %t.tu1.o // RUN: %{cxx} %s %{flags} %{compile_flags} -c -DTU2 -U_LIBCPP_ASSERTION_SEMANTIC -D_LIBCPP_ASSERTION_SEMANTIC=_LIBCPP_ASSERTION_SEMANTIC_OBSERVE -o %t.tu2.o // RUN: %{cxx} %s %{flags} %{compile_flags} -c -DTU3 -U_LIBCPP_ASSERTION_SEMANTIC -D_LIBCPP_ASSERTION_SEMANTIC=_LIBCPP_ASSERTION_SEMANTIC_QUICK_ENFORCE -o %t.tu3.o From 76119b18820ff5e775cf0bafc0cd3786604e1326 Mon Sep 17 00:00:00 2001 From: Konstantin Varlamov Date: Thu, 13 Nov 2025 17:57:19 -0800 Subject: [PATCH 10/11] Fix the check for C++03 in a test --- .../extensions/libcxx/odr_signature.assertion_semantics.sh.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libcxx/test/extensions/libcxx/odr_signature.assertion_semantics.sh.cpp b/libcxx/test/extensions/libcxx/odr_signature.assertion_semantics.sh.cpp index cf4f682d296ab..ea8da87bccb88 100644 --- a/libcxx/test/extensions/libcxx/odr_signature.assertion_semantics.sh.cpp +++ b/libcxx/test/extensions/libcxx/odr_signature.assertion_semantics.sh.cpp @@ -10,7 +10,7 @@ // XFAIL: msvc // Assertion semantics are not supported in C++03 mode -// UNSUPPORTED: std=c++03 +// UNSUPPORTED: c++03 // Test that we encode the assertion semantic in an ABI tag to avoid ODR violations when linking TUs that have different // values for it. From a6c5e9fa7e4add110a056ad06c6a4f5e593563a6 Mon Sep 17 00:00:00 2001 From: Konstantin Varlamov Date: Thu, 13 Nov 2025 20:30:45 -0800 Subject: [PATCH 11/11] Mark a test as unsupported, take 3 --- .../libcxx/odr_signature.assertion_semantics.sh.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libcxx/test/extensions/libcxx/odr_signature.assertion_semantics.sh.cpp b/libcxx/test/extensions/libcxx/odr_signature.assertion_semantics.sh.cpp index ea8da87bccb88..8ec1ec824c13c 100644 --- a/libcxx/test/extensions/libcxx/odr_signature.assertion_semantics.sh.cpp +++ b/libcxx/test/extensions/libcxx/odr_signature.assertion_semantics.sh.cpp @@ -9,8 +9,8 @@ // ABI tags have no effect in MSVC mode. // XFAIL: msvc -// Assertion semantics are not supported in C++03 mode -// UNSUPPORTED: c++03 +// Assertion semantics are not supported in C++03 mode and currently are experimental. +// UNSUPPORTED: c++03, libcpp-has-no-experimental-hardening-observe-semantic // Test that we encode the assertion semantic in an ABI tag to avoid ODR violations when linking TUs that have different // values for it.