[libcxx-commits] [libcxx] [libc++][hardening] Undeprecate safe mode (PR #68391)

Konstantin Varlamov via libcxx-commits libcxx-commits at lists.llvm.org
Fri Oct 6 00:22:49 PDT 2023


https://github.com/var-const created https://github.com/llvm/llvm-project/pull/68391

To allow for a smoother transition, keep the safe mode working as is in the LLVM 18 release (the first release that aims to make hardening available), then deprecate it in LLVM 19.

>From 0217474912b17788ab0b1b9a5e65c27e92fc74a0 Mon Sep 17 00:00:00 2001
From: Konstantin Varlamov <varconsteq at gmail.com>
Date: Fri, 6 Oct 2023 00:16:24 -0700
Subject: [PATCH] [libc++][hardening] Undeprecate safe mode

To allow for a smoother transition, keep the safe mode working as is in
the LLVM 18 release (the first release that aims to make hardening
  available), then deprecate it in LLVM 19.
---
 libcxx/CMakeLists.txt                         | 14 +++++---
 libcxx/docs/BuildingLibcxx.rst                |  9 +++++
 libcxx/docs/ReleaseNotes/18.rst               | 34 +++++++++----------
 libcxx/docs/UsingLibcxx.rst                   | 29 ++++++++++++++++
 libcxx/include/__config                       |  3 +-
 ...ling_assertions_enables_safe_mode.pass.cpp |  5 ++-
 6 files changed, 67 insertions(+), 27 deletions(-)

diff --git a/libcxx/CMakeLists.txt b/libcxx/CMakeLists.txt
index 68410feb9661816..16540caf68eaf04 100644
--- a/libcxx/CMakeLists.txt
+++ b/libcxx/CMakeLists.txt
@@ -48,6 +48,10 @@ include(CMakeDependentOption)
 include(HandleCompilerRT)
 
 # Basic options ---------------------------------------------------------------
+option(LIBCXX_ENABLE_ASSERTIONS
+  "Enable assertions inside the compiled library, and at the same time make it the
+   default when compiling user code. Note that assertions can be enabled or disabled
+   by users in their own code regardless of this option." OFF)
 option(LIBCXX_ENABLE_SHARED "Build libc++ as a shared library." ON)
 option(LIBCXX_ENABLE_STATIC "Build libc++ as a static library." ON)
 option(LIBCXX_ENABLE_FILESYSTEM
@@ -773,6 +777,11 @@ config_define_if_not(LIBCXX_ENABLE_WIDE_CHARACTERS _LIBCPP_HAS_NO_WIDE_CHARACTER
 config_define_if_not(LIBCXX_ENABLE_STD_MODULES _LIBCPP_HAS_NO_STD_MODULES)
 config_define_if_not(LIBCXX_ENABLE_TIME_ZONE_DATABASE _LIBCPP_HAS_NO_TIME_ZONE_DATABASE)
 config_define_if_not(LIBCXX_ENABLE_VENDOR_AVAILABILITY_ANNOTATIONS _LIBCPP_HAS_NO_VENDOR_AVAILABILITY_ANNOTATIONS)
+
+# 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)
@@ -790,11 +799,6 @@ elseif (LIBCXX_HARDENING_MODE STREQUAL "unchecked")
   config_define(0 _LIBCPP_ENABLE_SAFE_MODE_DEFAULT)
   config_define(0 _LIBCPP_ENABLE_DEBUG_MODE_DEFAULT)
 endif()
-# TODO(LLVM 19): Remove this after branching for LLVM 18, this is a simple
-# courtesy for vendors to be notified about this change.
-if (LIBCXX_ENABLE_ASSERTIONS)
-  message(FATAL_ERROR "LIBCXX_ENABLE_ASSERTIONS has been replaced by LIBCXX_HARDENING_MODE=safe")
-endif()
 
 if (LIBCXX_PSTL_CPU_BACKEND STREQUAL "serial")
   config_define(1 _LIBCPP_PSTL_CPU_BACKEND_SERIAL)
diff --git a/libcxx/docs/BuildingLibcxx.rst b/libcxx/docs/BuildingLibcxx.rst
index e919e1e6f32bfc3..a2041b7e74d8ebb 100644
--- a/libcxx/docs/BuildingLibcxx.rst
+++ b/libcxx/docs/BuildingLibcxx.rst
@@ -215,6 +215,15 @@ libc++ specific options
 
   Toggle the installation of the libc++ headers.
 
+.. option:: LIBCXX_ENABLE_ASSERTIONS:BOOL
+
+  **Default**: ``OFF``
+
+  Build libc++ with assertions enabled in the compiled library, and enable assertions
+  by default when building user code as well. Assertions can be turned off by users
+  by defining ``_LIBCPP_ENABLE_ASSERTIONS=0``. For details, see
+  :ref:`the documentation <assertions-mode>`.
+
 .. option:: LIBCXX_ENABLE_SHARED:BOOL
 
   **Default**: ``ON``
diff --git a/libcxx/docs/ReleaseNotes/18.rst b/libcxx/docs/ReleaseNotes/18.rst
index 640e6ce0769582c..d639f23eda643c8 100644
--- a/libcxx/docs/ReleaseNotes/18.rst
+++ b/libcxx/docs/ReleaseNotes/18.rst
@@ -35,12 +35,6 @@ see the `releases page <https://llvm.org/releases/>`_.
 What's New in Libc++ 18.0.0?
 ==============================
 
-- The "safe" mode is replaced by the hardened mode in this release. The
-  ``LIBCXX_ENABLE_ASSERTIONS`` CMake variable is deprecated and setting it will
-  trigger an error; use ``LIBCXX_HARDENING_MODE`` instead. Similarly, the
-  ``_LIBCPP_ENABLE_ASSERTIONS`` macro is deprecated and setting it to ``1`` now
-  enables the hardened mode. See ``libcxx/docs/Hardening.rst`` for more details.
-
 - A new debug mode has been added, replacing the legacy debug mode that was
   removed in the LLVM 17 release. See ``libcxx/docs/Hardening.rst`` for more
   details.
@@ -63,10 +57,9 @@ Improvements and New Features
   enabled on a per translation unit basis using the ``-D_LIBCPP_ENABLE_HARDENED_MODE=1`` macro. See
   :ref:`the hardening documentation <using-hardening-modes>` for more details.
 
-- The safe mode is now a part of hardening modes. Vendors can configure whether the safe mode is enabled by default
-  with the ``LIBCXX_HARDENING_MODE`` variable at CMake configuration time. Users can control whether the safe mode
-  is enabled on a per translation unit basis using the ``-D_LIBCPP_ENABLE_SAFE_MODE=1`` macro. The
-  ``_LIBCPP_ENABLE_ASSERTIONS`` macro that was previously used to enable the safe mode is now deprecated. See
+- The safe mode is now also a part of hardening modes. Vendors can configure whether the safe mode is enabled by
+  default with the ``LIBCXX_HARDENING_MODE`` variable at CMake configuration time. Users can control whether the safe
+  mode is enabled on a per translation unit basis using the ``-D_LIBCPP_ENABLE_SAFE_MODE=1`` 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
@@ -80,13 +73,6 @@ Improvements and New Features
 Deprecations and Removals
 -------------------------
 
-- The "safe" mode is now controlled via the new generalized support for hardening. The ``LIBCXX_ENABLE_ASSERTIONS``
-  CMake variable that was used to enable the safe mode is now 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
-  is deprecated (setting it to ``1`` still enables the safe mode in this release while also issuing a deprecation
-  warning). ``_LIBCPP_ENABLE_ASSERTIONS`` will be removed entirely in the next release and setting it will become an
-  error. See :ref:`the hardening documentation <using-hardening-modes>` for more details.
-
 - The non-conforming constructor ``std::future_error(std::error_code)`` has been removed. Please use the
   ``std::future_error(std::future_errc)`` constructor provided in C++17 instead.
 
@@ -109,6 +95,13 @@ LLVM 18
 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 in this
+  release while also issuing a deprecation warning). ``_LIBCPP_ENABLE_ASSERTIONS`` will be removed entirely in the next
+  release and setting it will become an error. See :ref:`the hardening documentation <using-hardening-modes>` for more
+  details.
+
 - The base template for ``std::char_traits`` has been marked as deprecated and will be removed in LLVM 19. If you
   are using ``std::char_traits`` with types other than ``char``, ``wchar_t``, ``char8_t``, ``char16_t``, ``char32_t``
   or a custom character type for which you specialized ``std::char_traits``, your code will stop working when we
@@ -117,6 +110,13 @@ LLVM 19
   Note that the ``_LIBCPP_CHAR_TRAITS_REMOVE_BASE_SPECIALIZATION`` macro can be defined in LLVM 18 to eagerly remove
   the specialization and prepare code bases for the unconditional removal in LLVM 19.
 
+LLVM 20
+~~~~~~~
+
+- The ``LIBCXX_ENABLE_ASSERTIONS`` CMake variable and the ``_LIBCPP_ENABLE_ASSERTIONS`` macro that were used to enable
+  the safe mode will be removed.
+
+
 ABI Affecting Changes
 ---------------------
 
diff --git a/libcxx/docs/UsingLibcxx.rst b/libcxx/docs/UsingLibcxx.rst
index ee4cd31a93526e9..e4763bc58a6b989 100644
--- a/libcxx/docs/UsingLibcxx.rst
+++ b/libcxx/docs/UsingLibcxx.rst
@@ -147,6 +147,35 @@ IWYU, you should run the tool like so:
 If you would prefer to not use that flag, then you can replace ``/path/to/include-what-you-use/share/libcxx.imp``
 file with the libc++-provided ``libcxx.imp`` file.
 
+.. _assertions-mode:
+
+Enabling the "safe libc++" mode
+===============================
+
+Libc++ contains a number of assertions whose goal is to catch undefined behavior in the
+library, usually caused by precondition violations. Those assertions do not aim to be
+exhaustive -- instead they aim to provide a good balance between safety and performance.
+In particular, these assertions do not change the complexity of algorithms. However, they
+might, in some cases, interfere with compiler optimizations.
+
+By default, these assertions are turned off. Vendors can decide to turn them on while building
+the compiled library by defining ``LIBCXX_ENABLE_ASSERTIONS=ON`` at CMake configuration time.
+When ``LIBCXX_ENABLE_ASSERTIONS`` is used, the compiled library will be built with assertions
+enabled, **and** user code will be built with assertions enabled by default. If
+``LIBCXX_ENABLE_ASSERTIONS=OFF`` at CMake configure time, the compiled library will not contain
+assertions and the default when building user code will be to have assertions disabled.
+As a user, you can consult your vendor to know whether assertions are enabled by default.
+
+Furthermore, independently of any vendor-selected default, users can always control whether
+assertions are enabled in their code by defining ``_LIBCPP_ENABLE_ASSERTIONS=0|1`` before
+including any libc++ header (we recommend passing ``-D_LIBCPP_ENABLE_ASSERTIONS=X`` to the
+compiler). Note that if the compiled library was built by the vendor without assertions,
+functions compiled inside the static or shared library won't have assertions enabled even
+if the user defines ``_LIBCPP_ENABLE_ASSERTIONS=1`` (the same is true for the inverse case
+where the static or shared library was compiled **with** assertions but the user tries to
+disable them). However, most of the code in libc++ is in the headers, so the user-selected
+value for ``_LIBCPP_ENABLE_ASSERTIONS`` (if any) will usually be respected.
+
 .. _termination-handler:
 
 Overriding the default termination handler
diff --git a/libcxx/include/__config b/libcxx/include/__config
index 52bf12f80a28b99..a4747424d2c19cd 100644
--- a/libcxx/include/__config
+++ b/libcxx/include/__config
@@ -219,11 +219,10 @@
 
 // HARDENING {
 
-// TODO(hardening): remove this in LLVM 19.
+// 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.
 #  ifdef _LIBCPP_ENABLE_ASSERTIONS
-#    warning "_LIBCPP_ENABLE_ASSERTIONS is deprecated, please use _LIBCPP_ENABLE_SAFE_MODE instead."
 #    if _LIBCPP_ENABLE_ASSERTIONS != 0 && _LIBCPP_ENABLE_ASSERTIONS != 1
 #      error "_LIBCPP_ENABLE_ASSERTIONS must be set to 0 or 1"
 #    endif
diff --git a/libcxx/test/libcxx/assertions/modes/enabling_assertions_enables_safe_mode.pass.cpp b/libcxx/test/libcxx/assertions/modes/enabling_assertions_enables_safe_mode.pass.cpp
index a4e3d5978155827..61cf26bd2ae142d 100644
--- a/libcxx/test/libcxx/assertions/modes/enabling_assertions_enables_safe_mode.pass.cpp
+++ b/libcxx/test/libcxx/assertions/modes/enabling_assertions_enables_safe_mode.pass.cpp
@@ -6,7 +6,7 @@
 //
 //===----------------------------------------------------------------------===//
 
-// TODO(hardening): remove in LLVM 19.
+// TODO(hardening): remove in LLVM 20.
 // This test ensures that enabling assertions now enables the safe mode.
 
 // Other hardening modes would additionally trigger the error that they are mutually exclusive.
@@ -15,8 +15,7 @@
 // UNSUPPORTED: c++03, !has-unix-headers
 // The ability to set a custom abort message is required to compare the assertion message.
 // XFAIL: availability-verbose_abort-missing
-// Ignore the warning about `_LIBCPP_ENABLE_ASSERTIONS` being deprecated.
-// ADDITIONAL_COMPILE_FLAGS: -Wno-error -D_LIBCPP_ENABLE_ASSERTIONS=1
+// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_ENABLE_ASSERTIONS=1
 
 #include <cassert>
 #include "check_assertion.h"



More information about the libcxx-commits mailing list