Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[libc++][hardening] Rework macros for enabling the hardening mode. #70575

Merged
merged 13 commits into from
Nov 8, 2023

Conversation

var-const
Copy link
Member

@var-const var-const commented Oct 28, 2023

  1. Instead of using individual "boolean" macros, have an "enum" macro
    _LIBCPP_HARDENING_MODE. This avoids issues with macros being
    mutually exclusive and makes overriding the hardening mode within a TU
    more straightforward.

  2. Rename the safe mode to debug-lite.

This brings the code in line with the RFC:
https://discourse.llvm.org/t/rfc-hardening-in-libc/73925

Fixes #65101

@var-const var-const requested a review from a team as a code owner October 28, 2023 21:43
@llvmbot llvmbot added the libc++ libc++ C++ Standard Library. Not GNU libstdc++. Not libc++abi. label Oct 28, 2023
@llvmbot
Copy link
Collaborator

llvmbot commented Oct 28, 2023

@llvm/pr-subscribers-libcxx

Author: Konstantin Varlamov (var-const)

Changes
  1. Instead of using individual "boolean" macros, have an "enum" macro
    _LIBCPP_HARDENING_MODE. This avoids issues with macros being
    mutually exclusive and makes overriding the hardening mode within a TU
    more straightforward.

  2. Rename the safe mode to debug-lite.

This brings the code in line with the RFC:
https://discourse.llvm.org/t/rfc-hardening-in-libc/73925


Patch is 50.98 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/70575.diff

33 Files Affected:

  • (modified) libcxx/CMakeLists.txt (+10-18)
  • (modified) libcxx/docs/Hardening.rst (+24-15)
  • (modified) libcxx/docs/ReleaseNotes/18.rst (+15-8)
  • (modified) libcxx/docs/UsingLibcxx.rst (+2-8)
  • (modified) libcxx/include/__algorithm/comp_ref_type.h (+1-1)
  • (modified) libcxx/include/__algorithm/three_way_comp_ref_type.h (+1-1)
  • (modified) libcxx/include/__config (+40-43)
  • (modified) libcxx/include/__config_site.in (+1-3)
  • (modified) libcxx/test/libcxx/algorithms/alg.sorting/alg.heap.operations/make.heap/complexity.pass.cpp (+1-1)
  • (renamed) libcxx/test/libcxx/assertions/modes/debug_lite.pass.cpp (+2-2)
  • (removed) libcxx/test/libcxx/assertions/modes/debug_mode_disabled_in_tu.pass.cpp (-23)
  • (removed) libcxx/test/libcxx/assertions/modes/debug_mode_not_1_or_0.verify.cpp (-19)
  • (modified) libcxx/test/libcxx/assertions/modes/enabling_assertions_enables_safe_mode.pass.cpp (+4-5)
  • (removed) libcxx/test/libcxx/assertions/modes/hardened_and_debug_mutually_exclusive.verify.cpp (-18)
  • (removed) libcxx/test/libcxx/assertions/modes/hardened_and_safe_mutually_exclusive.verify.cpp (-18)
  • (removed) libcxx/test/libcxx/assertions/modes/hardened_mode_disabled_in_tu.pass.cpp (-23)
  • (renamed) libcxx/test/libcxx/assertions/modes/hardening_mode_incorrect_value.verify.cpp (+4-5)
  • (added) libcxx/test/libcxx/assertions/modes/override_with_debug_lite_mode.pass.cpp (+30)
  • (renamed) libcxx/test/libcxx/assertions/modes/override_with_debug_mode.pass.cpp (+9-9)
  • (renamed) libcxx/test/libcxx/assertions/modes/override_with_hardened_mode.pass.cpp (+5-6)
  • (renamed) libcxx/test/libcxx/assertions/modes/override_with_unchecked_mode.pass.cpp (+3-7)
  • (removed) libcxx/test/libcxx/assertions/modes/safe_and_debug_mutually_exclusive.verify.cpp (-18)
  • (removed) libcxx/test/libcxx/assertions/modes/safe_mode_disabled_in_tu.pass.cpp (-23)
  • (removed) libcxx/test/libcxx/assertions/modes/safe_mode_not_1_or_0.verify.cpp (-19)
  • (modified) libcxx/test/libcxx/odr_signature.hardening.sh.cpp (+5-11)
  • (modified) libcxx/test/std/algorithms/alg.sorting/alg.heap.operations/sort.heap/complexity.pass.cpp (+1-1)
  • (modified) libcxx/test/std/algorithms/alg.sorting/alg.heap.operations/sort.heap/ranges_sort_heap.pass.cpp (+1-1)
  • (modified) libcxx/test/std/algorithms/alg.sorting/alg.merge/inplace_merge_comp.pass.cpp (+1-1)
  • (modified) libcxx/test/std/algorithms/alg.sorting/alg.three.way/lexicographical_compare_three_way_comp.pass.cpp (+1-1)
  • (modified) libcxx/test/support/container_debug_tests.h (+1-1)
  • (modified) libcxx/utils/ci/buildkite-pipeline.yml (+2-2)
  • (modified) libcxx/utils/libcxx/test/params.py (+5-4)
  • (modified) llvm/utils/gn/secondary/libcxx/include/BUILD.gn (+1-3)
diff --git a/libcxx/CMakeLists.txt b/libcxx/CMakeLists.txt
index d03421afde1e755..b9f7ab8466aa806 100644
--- a/libcxx/CMakeLists.txt
+++ b/libcxx/CMakeLists.txt
@@ -59,7 +59,7 @@ option(LIBCXX_ENABLE_FILESYSTEM
    available on the platform. This includes things like most parts of <filesystem> and
    others like <fstream>" ON)
 option(LIBCXX_INCLUDE_TESTS "Build the libc++ tests." ${LLVM_INCLUDE_TESTS})
-set(LIBCXX_SUPPORTED_HARDENING_MODES unchecked hardened safe debug)
+set(LIBCXX_SUPPORTED_HARDENING_MODES unchecked hardened debug_lite debug)
 set(LIBCXX_HARDENING_MODE "unchecked" CACHE STRING
   "Specify the default hardening mode to use. This mode will be used inside the
    compiled library and will be the default when compiling user code. Note that
@@ -752,24 +752,16 @@ config_define_if_not(LIBCXX_ENABLE_VENDOR_AVAILABILITY_ANNOTATIONS _LIBCPP_HAS_N
 
 # TODO(LLVM 19): Produce a deprecation warning.
 if (LIBCXX_ENABLE_ASSERTIONS)
-  set(LIBCXX_HARDENING_MODE "safe")
-endif()
-if (LIBCXX_HARDENING_MODE STREQUAL "hardened")
-  config_define(1 _LIBCPP_ENABLE_HARDENED_MODE_DEFAULT)
-  config_define(0 _LIBCPP_ENABLE_SAFE_MODE_DEFAULT)
-  config_define(0 _LIBCPP_ENABLE_DEBUG_MODE_DEFAULT)
-elseif (LIBCXX_HARDENING_MODE STREQUAL "safe")
-  config_define(0 _LIBCPP_ENABLE_HARDENED_MODE_DEFAULT)
-  config_define(1 _LIBCPP_ENABLE_SAFE_MODE_DEFAULT)
-  config_define(0 _LIBCPP_ENABLE_DEBUG_MODE_DEFAULT)
+  set(LIBCXX_HARDENING_MODE "debug_lite")
+endif()
+if (LIBCXX_HARDENING_MODE STREQUAL "unchecked")
+  config_define(2 _LIBCPP_HARDENING_MODE_DEFAULT)
+elseif (LIBCXX_HARDENING_MODE STREQUAL "hardened")
+  config_define(4 _LIBCPP_HARDENING_MODE_DEFAULT)
+elseif (LIBCXX_HARDENING_MODE STREQUAL "debug_lite")
+  config_define(16 _LIBCPP_HARDENING_MODE_DEFAULT)
 elseif (LIBCXX_HARDENING_MODE STREQUAL "debug")
-  config_define(0 _LIBCPP_ENABLE_HARDENED_MODE_DEFAULT)
-  config_define(0 _LIBCPP_ENABLE_SAFE_MODE_DEFAULT)
-  config_define(1 _LIBCPP_ENABLE_DEBUG_MODE_DEFAULT)
-elseif (LIBCXX_HARDENING_MODE STREQUAL "unchecked")
-  config_define(0 _LIBCPP_ENABLE_HARDENED_MODE_DEFAULT)
-  config_define(0 _LIBCPP_ENABLE_SAFE_MODE_DEFAULT)
-  config_define(0 _LIBCPP_ENABLE_DEBUG_MODE_DEFAULT)
+  config_define(8 _LIBCPP_HARDENING_MODE_DEFAULT)
 endif()
 
 if (LIBCXX_PSTL_CPU_BACKEND STREQUAL "serial")
diff --git a/libcxx/docs/Hardening.rst b/libcxx/docs/Hardening.rst
index ec115d3d6012bfe..738fd3235d12e22 100644
--- a/libcxx/docs/Hardening.rst
+++ b/libcxx/docs/Hardening.rst
@@ -17,25 +17,25 @@ and are intended to be used in production.
 
 In addition to the hardened mode, libc++ also provides two other hardening
 modes:
-- safe mode;
+- debug-lite mode;
 - debug mode.
 
-The safe mode contains all the checks from the hardened mode and additionally
-some checks for undefined behavior that incur relatively little overhead but
-aren't security-critical. While the performance penalty is somewhat more
-significant compared to the hardened mode, the safe mode is still intended to be
-usable in production.
+The debug-lite mode contains all the checks from the hardened mode and
+additionally some checks for undefined behavior that incur relatively little
+overhead but aren't security-critical. While the performance penalty is somewhat
+more significant compared to the hardened mode, the debug-lite mode is still
+intended to be usable in production.
 
-The debug mode, in turn, contains all the checks from the safe mode and
+The debug mode, in turn, contains all the checks from the debug-lite mode and
 additionally more expensive checks that may affect the complexity of algorithms.
 The debug mode is intended to be used for testing, not in production.
 
 Vendors can set the default hardening mode by using the
 ``LIBCXX_HARDENING_MODE`` variable at CMake configuration time. Setting
 ``LIBCXX_HARDENING_MODE`` to ``hardened`` enables the hardened mode, and
-similarly setting the variable to ``safe`` enables the safe mode, and to
-``debug`` enables the debug mode. The default value is ``unchecked`` which
-doesn't enable any hardening.
+similarly setting the variable to ``debug_lite`` enables the debug-lite mode,
+and to ``debug`` enables the debug mode. The default value is ``unchecked``
+which doesn't enable any hardening.
 
 When hardening is enabled, the compiled library is built with the corresponding
 mode enabled, **and** user code will be built with the same mode enabled by
@@ -45,17 +45,26 @@ user code will be to have assertions disabled. As a user, you can consult your
 vendor to know which level of hardening is enabled by default.
 
 Furthermore, independently of any vendor-selected default, users can always
-control which level of hardening is enabled in their code by defining
-``_LIBCPP_ENABLE_HARDENED_MODE=0|1`` (or ``_LIBCPP_ENABLE_SAFE_MODE=0|1``, or
-``_LIBCPP_ENABLE_DEBUG_MODE=0|1``) before including any libc++ header (we
-recommend passing ``-D_LIBCPP_ENABLE_HARDENED_MODE=X``, etc. to the compiler).
+control which level of hardening is enabled in their code by defining the macro
+``_LIBCPP_HARDENING_MODE`` before including any libc++ headers (preferably by
+passing ``-D_LIBCPP_HARDENING_MODE=X`` to the compiler). The macro can be
+set to one of the following possible values:
+
+- ``_LIBCPP_HARDENING_MODE_UNCHECKED``;
+- ``_LIBCPP_HARDENING_MODE_HARDENED``;
+- ``_LIBCPP_HARDENING_MODE_DEBUG_LITE``;
+- ``_LIBCPP_HARDENING_MODE_DEBUG``.
+
+The exact numeric values of these macros are unspecified and you should not rely
+on them (e.g. expect the values to be sorted in any way).
+
 Note that if the compiled library was built by the vendor in the unchecked mode,
 functions compiled inside the static or shared library won't have any hardening
 enabled even if the user compiles with hardening enabled (the same is true for
 the inverse case where the static or shared library was compiled **with**
 hardening enabled but the user tries to disable it). However, most of the code
 in libc++ is in the headers, so the user-selected value for
-``_LIBCPP_ENABLE_HARDENED|SAFE|DEBUG_MODE``, if any, will usually be respected.
+``_LIBCPP_HARDENING_MODE``, if any, will usually be respected.
 
 Enabling hardening has no impact on the ABI.
 
diff --git a/libcxx/docs/ReleaseNotes/18.rst b/libcxx/docs/ReleaseNotes/18.rst
index ac78563aa73848f..d0f28a53dbee6ea 100644
--- a/libcxx/docs/ReleaseNotes/18.rst
+++ b/libcxx/docs/ReleaseNotes/18.rst
@@ -58,16 +58,23 @@ Improvements and New Features
 - The library now provides a hardened mode under which common cases of library undefined behavior will be turned into
   a reliable program termination. Vendors can configure whether the hardened mode is enabled by default with the
   ``LIBCXX_HARDENING_MODE`` variable at CMake configuration time. Users can control whether the hardened mode is
-  enabled on a per translation unit basis using the ``-D_LIBCPP_ENABLE_HARDENED_MODE=1`` macro. See
+  enabled on a per translation unit basis using the ``_LIBCPP_HARDENING_MODE`` macro. See
   :ref:`the hardening documentation <using-hardening-modes>` for more details.
 
-- The library now provides a debug mode which is a superset of the safe mode, additionally enabling more expensive
+- The library now provides a debug-lite mode which is a superset of the hardened mode, additionally enabling checks that
+  catch common logic errors that aren't necessarily security-critical. This mode is largely a replacement for the safe
+  release. Unlike the legacy debug mode, this doesn't affect the ABI and doesn't require locking. Vendors can configure
+  whether the debug-lite mode is enabled by default with the ``LIBCXX_HARDENING_MODE`` variable at CMake configuration
+  time. ``LIBCXX_HARDENING_MODE`` variable at CMake configuration time. Users can control whether the hardened mode is
+  enabled on a per translation unit basis using the ``_LIBCPP_HARDENING_MODE`` macro. See
+  :ref:`the hardening documentation <using-hardening-modes>` for more details.
+
+- The library now provides a debug mode which is a superset of the debug-lite mode, additionally enabling more expensive
   checks that are not suitable to be used in production. This replaces the legacy debug mode that was removed in this
   release. Unlike the legacy debug mode, this doesn't affect the ABI and doesn't require locking. Vendors can configure
   whether the debug mode is enabled by default with the ``LIBCXX_HARDENING_MODE`` variable at CMake configuration time.
-  Users can control whether the debug mode is enabled on a per translation unit basis using the
-  ``-D_LIBCPP_ENABLE_DEBUG_MODE=1`` macro. See :ref:`the hardening documentation <using-hardening-modes>` for more
-  details.
+  Users can control whether the debug mode is enabled on a per translation unit basis using the ``_LIBCPP_HARDENING_MODE``
+  macro. See :ref:`the hardening documentation <using-hardening-modes>` for more details.
 
 Deprecations and Removals
 -------------------------
@@ -82,7 +89,7 @@ LLVM 18
 ~~~~~~~
 
 - The ``_LIBCPP_AVAILABILITY_CUSTOM_VERBOSE_ABORT_PROVIDED`` macro will not be honored anymore in LLVM 18.
-  Please see the updated documentation about the safe libc++ mode and in particular the ``_LIBCPP_VERBOSE_ABORT``
+  Please see the updated documentation about the hardened libc++ mode and in particular the ``_LIBCPP_VERBOSE_ABORT``
   macro for details.
 
 - The headers ``<experimental/deque>``, ``<experimental/forward_list>``, ``<experimental/list>``,
@@ -95,8 +102,8 @@ LLVM 19
 ~~~~~~~
 
 - The ``LIBCXX_ENABLE_ASSERTIONS`` CMake variable that was used to enable the safe mode will be deprecated and setting
-  it will trigger an error; use the ``LIBCXX_HARDENING_MODE`` variable with the value ``safe`` instead. Similarly, the
-  ``_LIBCPP_ENABLE_ASSERTIONS`` macro will be deprecated (setting it to ``1`` still enables the safe mode the LLVM 19
+  it will trigger an error; use the ``LIBCXX_HARDENING_MODE`` variable with the value ``debug_lite`` instead. Similarly, the
+  ``_LIBCPP_ENABLE_ASSERTIONS`` macro will be deprecated (setting it to ``1`` still enables the debug-lite mode the LLVM 19
   release while also issuing a deprecation warning). See :ref:`the hardening documentation <using-hardening-modes>` for
   more details.
 
diff --git a/libcxx/docs/UsingLibcxx.rst b/libcxx/docs/UsingLibcxx.rst
index 52c76f3b10548fb..24d6a7b95f5b2e4 100644
--- a/libcxx/docs/UsingLibcxx.rst
+++ b/libcxx/docs/UsingLibcxx.rst
@@ -223,14 +223,8 @@ safety annotations.
   ``std::mutex`` and ``std::lock_guard``. By default, these annotations are
   disabled and must be manually enabled by the user.
 
-**_LIBCPP_ENABLE_HARDENED_MODE**:
-  This macro is used to enable the :ref:`hardened mode <using-hardening-modes>`.
-
-**_LIBCPP_ENABLE_SAFE_MODE**:
-  This macro is used to enable the :ref:`safe mode <using-hardening-modes>`.
-
-**_LIBCPP_ENABLE_DEBUG_MODE**:
-  This macro is used to enable the :ref:`debug mode <using-hardening-modes>`.
+**_LIBCPP_HARDENING_MODE**:
+  This macro is used to choose the :ref:`hardening mode <using-hardening-modes>`.
 
 **_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS**:
   This macro is used to disable all visibility annotations inside libc++.
diff --git a/libcxx/include/__algorithm/comp_ref_type.h b/libcxx/include/__algorithm/comp_ref_type.h
index d16bd0f5310003f..2aeb55f550b53c2 100644
--- a/libcxx/include/__algorithm/comp_ref_type.h
+++ b/libcxx/include/__algorithm/comp_ref_type.h
@@ -65,7 +65,7 @@ struct __debug_less
 
 // Pass the comparator by lvalue reference. Or in debug mode, using a
 // debugging wrapper that stores a reference.
-#if _LIBCPP_ENABLE_DEBUG_MODE
+#  if _LIBCPP_HARDENING_MODE == _LIBCPP_HARDENING_MODE_DEBUG
 template <class _Comp>
 using __comp_ref_type = __debug_less<_Comp>;
 #else
diff --git a/libcxx/include/__algorithm/three_way_comp_ref_type.h b/libcxx/include/__algorithm/three_way_comp_ref_type.h
index 7731c0fd791d809..8fd15c5d66f2fc9 100644
--- a/libcxx/include/__algorithm/three_way_comp_ref_type.h
+++ b/libcxx/include/__algorithm/three_way_comp_ref_type.h
@@ -58,7 +58,7 @@ struct __debug_three_way_comp {
 
 // Pass the comparator by lvalue reference. Or in debug mode, using a
 // debugging wrapper that stores a reference.
-#  if _LIBCPP_ENABLE_DEBUG_MODE
+#  if _LIBCPP_HARDENING_MODE == _LIBCPP_HARDENING_MODE_DEBUG
 template <class _Comp>
 using __three_way_comp_ref_type = __debug_three_way_comp<_Comp>;
 #  else
diff --git a/libcxx/include/__config b/libcxx/include/__config
index 4bf171f998c6f05..d5aa49f72934640 100644
--- a/libcxx/include/__config
+++ b/libcxx/include/__config
@@ -217,33 +217,36 @@
 
 // TODO(hardening): deprecate this in LLVM 19.
 // This is for backward compatibility -- make enabling `_LIBCPP_ENABLE_ASSERTIONS` (which predates hardening modes)
-// equivalent to setting the safe mode.
+// equivalent to setting the debug-lite mode.
 #  ifdef _LIBCPP_ENABLE_ASSERTIONS
 #    if _LIBCPP_ENABLE_ASSERTIONS != 0 && _LIBCPP_ENABLE_ASSERTIONS != 1
 #      error "_LIBCPP_ENABLE_ASSERTIONS must be set to 0 or 1"
 #    endif
 #    if _LIBCPP_ENABLE_ASSERTIONS
-#      define _LIBCPP_ENABLE_SAFE_MODE 1
+#      define _LIBCPP_HARDENING_MODE _LIBCPP_HARDENING_MODE_DEBUG_LITE
 #    endif
 #  endif
 
+// The library provides the macro `_LIBCPP_HARDENING_MODE` which can be set to one of the following values:
+// - `_LIBCPP_HARDENING_MODE_UNCHECKED`;
+// - `_LIBCPP_HARDENING_MODE_HARDENED`;
+// - `_LIBCPP_HARDENING_MODE_DEBUG_LITE`;
+// - `_LIBCPP_HARDENING_MODE_DEBUG`.
+
 // Enables the hardened mode which consists of all checks intended to be used in production. Hardened mode prioritizes
-// security-critical checks that can be done with relatively little overhead in constant time. Mutually exclusive with
-// `_LIBCPP_ENABLE_SAFE_MODE` and `_LIBCPP_ENABLE_DEBUG_MODE`.
+// security-critical checks that can be done with relatively little overhead in constant time.
 //
-// #define _LIBCPP_ENABLE_HARDENED_MODE 1
+// #define _LIBCPP_HARDENING_MODE_HARDENED 1
 
-// Enables the safe mode which extends the hardened mode with checks that are relatively cheap and prevent common types
-// of errors but are not security-critical. Mutually exclusive with `_LIBCPP_ENABLE_HARDENED_MODE` and
-// `_LIBCPP_ENABLE_DEBUG_MODE`.
+// Enables the debug-lite mode which extends the hardened mode with checks that are relatively cheap and prevent common
+// types of errors but are not security-critical.
 //
-// #define _LIBCPP_ENABLE_SAFE_MODE 1
+// #define _LIBCPP_HARDENING_MODE_DEBUG_LITE 1
 
 // Enables the debug mode which contains all the checks from the hardened mode and additionally more expensive checks
 // that may affect the complexity of algorithms. The debug mode is intended to be used for testing, not in production.
-// Mutually exclusive with `_LIBCPP_ENABLE_HARDENED_MODE` and `_LIBCPP_ENABLE_SAFE_MODE`.
 //
-// #define _LIBCPP_ENABLE_DEBUG_MODE 1
+// #define _LIBCPP_HARDENING_MODE_DEBUG 1
 
 // 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.
@@ -269,38 +272,32 @@
 //
 // - `_LIBCPP_ASSERT_UNCATEGORIZED` -- for assertions that haven't been properly classified yet.
 
-#  ifndef _LIBCPP_ENABLE_HARDENED_MODE
-#    define _LIBCPP_ENABLE_HARDENED_MODE _LIBCPP_ENABLE_HARDENED_MODE_DEFAULT
-#  endif
-#  if _LIBCPP_ENABLE_HARDENED_MODE != 0 && _LIBCPP_ENABLE_HARDENED_MODE != 1
-#    error "_LIBCPP_ENABLE_HARDENED_MODE must be set to 0 or 1."
-#  endif
-
-#  ifndef _LIBCPP_ENABLE_SAFE_MODE
-#    define _LIBCPP_ENABLE_SAFE_MODE _LIBCPP_ENABLE_SAFE_MODE_DEFAULT
-#  endif
-#  if _LIBCPP_ENABLE_SAFE_MODE != 0 && _LIBCPP_ENABLE_SAFE_MODE != 1
-#    error "_LIBCPP_ENABLE_SAFE_MODE must be set to 0 or 1."
-#  endif
+// clang-format off
+#  define _LIBCPP_HARDENING_MODE_UNCHECKED  (1 << 1)
+#  define _LIBCPP_HARDENING_MODE_HARDENED   (1 << 2)
+#  define _LIBCPP_HARDENING_MODE_DEBUG_LITE (1 << 4) // Deliberately not ordered.
+#  define _LIBCPP_HARDENING_MODE_DEBUG      (1 << 3)
+// clang-format on
 
-#  ifndef _LIBCPP_ENABLE_DEBUG_MODE
-#    define _LIBCPP_ENABLE_DEBUG_MODE _LIBCPP_ENABLE_DEBUG_MODE_DEFAULT
-#  endif
-#  if _LIBCPP_ENABLE_DEBUG_MODE != 0 && _LIBCPP_ENABLE_DEBUG_MODE != 1
-#    error "_LIBCPP_ENABLE_DEBUG_MODE must be set to 0 or 1."
+#  ifndef _LIBCPP_HARDENING_MODE
+#    define _LIBCPP_HARDENING_MODE _LIBCPP_HARDENING_MODE_DEFAULT
 #  endif
 
-#  if (_LIBCPP_ENABLE_HARDENED_MODE && _LIBCPP_ENABLE_SAFE_MODE) ||                                                    \
-      (_LIBCPP_ENABLE_HARDENED_MODE && _LIBCPP_ENABLE_DEBUG_MODE) ||                                                   \
-      (_LIBCPP_ENABLE_SAFE_MODE && _LIBCPP_ENABLE_DEBUG_MODE)
-#    error                                                                                                             \
-        "Only one of _LIBCPP_ENABLE_HARDENED_MODE, _LIBCPP_ENABLE_SAFE_MODE and _LIBCPP_ENABLE_DEBUG_MODE can be enabled."
+#  if _LIBCPP_HARDENING_MODE != _LIBCPP_HARDENING_MODE_UNCHECKED &&                                                    \
+      _LIBCPP_HARDENING_MODE != _LIBCPP_HARDENING_MODE_HARDENED &&                                                     \
+      _LIBCPP_HARDENING_MODE != _LIBCPP_HARDENING_MODE_DEBUG_LITE &&                                                   \
+      _LIBCPP_HARDENING_MODE != _LIBCPP_HARDENING_MODE_DEBUG
+#    error _LIBCPP_HARDENING_MODE must be set to one of the following values: \
+_LIBCPP_HARDENING_MODE_UNCHECKED, \
+_LIBCPP_HARDENING_MODE_HARDENED, \
+_LIBCPP_HARDENING_MODE_DEBUG_LITE, \
+_LIBCPP_HARDENING_MODE_DEBUG
 #  endif
 
 // clang-format off
 // Hardened mode checks.
 
-#  if _LIBCPP_ENABLE_HARDENED_MODE
+#  if _LIBCPP_HARDENING_MODE == _LIBCPP_HARDENING_MODE_HARDENED
 
 // Enabled checks.
 #    define _LIBCPP_ASSERT_VALID_INPUT_RANGE(expression, message)        _LIBCPP_ASSERT(expression, message)
@@ -313,9 +310,9 @@
 #    define _LIBCPP_ASSERT_INTERNAL(expression, message)                 _LIBCPP_ASSUME(expression)
 #    define _LIBCPP_ASSERT_UNCATEGORIZED(expression, message)            _LIBCPP_ASSUME(expression)
 
-// Safe mode checks.
+// Debug-lite mode checks.
 
-#  elif _LIBCPP_ENABLE_SAFE_MODE
+#  elif _LIBCPP_HARDENING_MODE == _LIBCPP_HARDENING_MODE_DEBUG_LITE
 
 // Enabled checks.
 #    define _LIBCPP_ASSERT_VALID_INPUT_RANGE(expression, message)        _LIBCPP_ASSERT(expression, message)
@@ -328,7 +325,7 @@
 
 // Debug mode checks.
 
-#  elif _LIBCPP_ENABLE_DEBUG_MODE
+#  elif _LIBCPP_HARDENING_MODE == _LIBCPP_HARDENING_MODE_DEBUG
 
 // All checks enabled.
 #    define _LIBCPP_ASSERT_VALID_INPUT_RANGE(expression, message)         _LIBCPP_ASSERT(expression, message)
@@ -350,7 +347,7 @@
 #    define _LIBCPP_ASSERT_INTERNAL(expression, message)                  _LIBCPP_ASSUME(expression)
 #    define _LIBCPP_ASSERT_UNCATEGORIZED(expression, message)             _LIBCPP_ASSUME(expression)
 
-#  endif // _LIBCPP_ENABLE_HARDENED_MODE
+#  endif // _LIBCPP_HARDENING_MODE == _LIBCPP_HARDENING_MODE_HARDENED
 // clang-format on
 
 // } HARDENING
@@ -730,11 +727,11 @@ typedef __char32_t char32_t;
 #    define _LIBCPP_EXCLUDE_FROM_EXPLICIT_INSTANTIATION _LIBCPP_ALWAYS_INLINE
 #  endif
 
-#  if _LIBCPP_ENABLE_HARDENED_MODE
+#  if _LIBCPP_HARDENING_MODE == _LIBCPP_HARDENING_MODE_HARDENED
 #    define _LIBCPP_HARDENING_SIG h
-#  elif _LIBCPP_ENABLE_SAFE_MODE
-#    define _LIBCPP_HARDENING_SIG s
-#  elif _LIBCPP_ENABLE_DEBUG_MODE
+#  elif _LIBCPP_HARDENING_MODE == _LIBCPP_HARDENING_MODE_DEBUG_LITE
+#    define _LIBCPP_HARDENING_SIG s // "safe"
+#  elif _LIBCPP_HARDENING_MODE == _LIBCPP_HARDENING_MODE_DEBUG
 #    define _LIBCPP_HARDENING_SIG d
 #  else
 #    define _LIBCPP_HARDENING_SIG u // for unchecked
diff --git a/libcxx/include/__config_site.in b/libcxx/include/__config_site.in
index c85cbcd02c441b9..6cade6f10d8acc1 100644
--- a/libcxx/include/__config_site.in
+++ b/libcxx/include/__config_site.in
@@ -36,9 +36,7 @@
 #cmakedefine _LIBCPP_PSTL_CPU_BACKEND_LIBDISPATCH
 
 // Hardening.
-#cmakedefine01 _LIBCPP_ENABLE_HARDENED_MODE_DEFAULT
-#cmakedefine01 _LIBCPP_ENABLE_SAFE_MODE_DEFAULT
-#cmakedefine01 _LIBCPP_ENABLE_DEBUG_MODE_DEFAULT
+#cmakedefine _LIBCPP_HARDENING_MODE_DEFAULT @_LIBCPP_HARDENING_MODE_DEFAULT@
 
 // __USE_MINGW_ANSI_STDIO gets redefined on MinGW
 #ifdef __clang__
diff --git a/libcxx/test/libcxx/algorithms/alg.sorting/alg.heap.ope...
[truncated]

libcxx/include/__config Outdated Show resolved Hide resolved
llvm/utils/gn/secondary/libcxx/include/BUILD.gn Outdated Show resolved Hide resolved
libcxx/utils/libcxx/test/params.py Outdated Show resolved Hide resolved
@github-actions
Copy link

github-actions bot commented Oct 28, 2023

✅ With the latest revision this PR passed the C/C++ code formatter.

@var-const var-const added the hardening Issues related to the hardening effort label Oct 29, 2023
@ldionne ldionne self-assigned this Oct 31, 2023
libcxx/docs/Hardening.rst Outdated Show resolved Hide resolved
libcxx/docs/ReleaseNotes/18.rst Outdated Show resolved Hide resolved
libcxx/include/__config Outdated Show resolved Hide resolved
libcxx/include/__config Outdated Show resolved Hide resolved
libcxx/utils/libcxx/test/params.py Outdated Show resolved Hide resolved
llvm/utils/gn/secondary/libcxx/include/BUILD.gn Outdated Show resolved Hide resolved
@var-const var-const force-pushed the varconst/hardening-rework-macros branch from 26bbe1c to 10625a9 Compare November 2, 2023 02:32
Copy link
Member

@ldionne ldionne left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is looking really good!

libcxx/cmake/caches/Generic-fast-hardening-mode.cmake Outdated Show resolved Hide resolved
libcxx/docs/ReleaseNotes/18.rst Outdated Show resolved Hide resolved
libcxx/include/__config Outdated Show resolved Hide resolved
libcxx/test/libcxx/odr_signature.hardening.sh.cpp Outdated Show resolved Hide resolved
@var-const
Copy link
Member Author

var-const commented Nov 2, 2023

Heads-up to @llvm/libcxx-vendors -- this patch reflects our current proposal for naming hardening modes (see the comment on the RFC). We plan to merge this patch early next week; ideally we'd avoid changing the names after the patch is merged to minimize disruption to those of you who use the main branch. If you have any objection to the names / other feedback on the patch, please let us know!

1. Instead of using individual "boolean" macros, have an "enum" macro
`_LIBCPP_HARDENING_MODE`. This avoids issues with macros being
mutually exclusive and makes overriding the hardening mode within a TU
more straightforward.

2. Rename the safe mode to debug-lite.

This brings the code in line with the RFC:
https://discourse.llvm.org/t/rfc-hardening-in-libc/73925
- Switch to the (none|fast|strict|debug) naming scheme.
@var-const var-const force-pushed the varconst/hardening-rework-macros branch from b41e169 to 1999c6f Compare November 8, 2023 03:03
Copy link
Member

@ldionne ldionne left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

@var-const var-const merged commit 64d413e into llvm:main Nov 8, 2023
5 checks passed
@var-const var-const deleted the varconst/hardening-rework-macros branch November 8, 2023 19:10
@Artem-B
Copy link
Member

Artem-B commented Nov 8, 2023

It appears that we still have some places where the hardening mode is set to "safe". E.g.

set(LIBCXX_HARDENING_MODE "safe")

@Caslyn
Copy link
Contributor

Caslyn commented Nov 8, 2023

Hi @var-const, we are seeing errors on our downstream builders due to #70575 (comment). Could you revert this change if a fix cannot be submitted right away?

@var-const
Copy link
Member Author

@Caslyn @Artem-B Thank you for the heads-up, will merge a fix shortly.

@var-const
Copy link
Member Author

var-const commented Nov 8, 2023

@Caslyn @Artem-B #71743 should fix it.

Update: merged now. Sorry about the trouble! Please let me know if there are still any broken builds.

var-const added a commit to var-const/llvm-project that referenced this pull request Nov 8, 2023
var-const added a commit that referenced this pull request Nov 8, 2023
gnoliyil pushed a commit to gnoliyil/fuchsia that referenced this pull request Jan 27, 2024
llvm/llvm-project#70575 changed libcpp hardening
mode semantics such that clang will now generate this error if a
LIBCPP_HARDENING_MODE or its default is not defined to an accepted
value:

```
_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
```

This CL inserts the default hardening mode to none in
ktl/include/__config_site to resolve the above error that's generated
for Fuchsia *when* a hardening mode is not set.

Fixed: 136228
Change-Id: I9fecb18bf851900868e501b52ebd6ae6377a81a0
Reviewed-on: https://fuchsia-review.googlesource.com/c/fuchsia/+/944786
Reviewed-by: Joshua Seaton <joshuaseaton@google.com>
Fuchsia-Auto-Submit: Caslyn Tonelli <caslyn@google.com>
Commit-Queue: Auto-Submit <auto-submit@fuchsia-infra.iam.gserviceaccount.com>
Reviewed-by: Petr Hosek <phosek@google.com>
qihangkong pushed a commit to rvgpu/llvm that referenced this pull request Apr 18, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
hardening Issues related to the hardening effort libc++ libc++ C++ Standard Library. Not GNU libstdc++. Not libc++abi.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[libc++][hardening] Make it possible to mix and match different hardening modes across different TUs
5 participants