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

Konstantin Varlamov via libcxx-commits libcxx-commits at lists.llvm.org
Fri Oct 6 19:59:12 PDT 2023


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

>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 1/2] [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"

>From 33f13b58d43f6cdbf807485bd9b3e80773140d0b Mon Sep 17 00:00:00 2001
From: Konstantin Varlamov <varconsteq at gmail.com>
Date: Fri, 6 Oct 2023 19:58:10 -0700
Subject: [PATCH 2/2] Address feedback

---
 libcxx/docs/BuildingLibcxx.rst  |  9 ---------
 libcxx/docs/ReleaseNotes/18.rst | 12 +++---------
 libcxx/docs/UsingLibcxx.rst     | 29 -----------------------------
 3 files changed, 3 insertions(+), 47 deletions(-)

diff --git a/libcxx/docs/BuildingLibcxx.rst b/libcxx/docs/BuildingLibcxx.rst
index a2041b7e74d8ebb..e919e1e6f32bfc3 100644
--- a/libcxx/docs/BuildingLibcxx.rst
+++ b/libcxx/docs/BuildingLibcxx.rst
@@ -215,15 +215,6 @@ 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 d639f23eda643c8..02f8276c590a15b 100644
--- a/libcxx/docs/ReleaseNotes/18.rst
+++ b/libcxx/docs/ReleaseNotes/18.rst
@@ -57,11 +57,6 @@ 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 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
   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
@@ -97,10 +92,9 @@ 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.
+  ``_LIBCPP_ENABLE_ASSERTIONS`` macro will be deprecated (setting it to ``1`` still enables the safe mode the LLVM 19
+  release while also issuing a deprecation warning). 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``
diff --git a/libcxx/docs/UsingLibcxx.rst b/libcxx/docs/UsingLibcxx.rst
index e4763bc58a6b989..ee4cd31a93526e9 100644
--- a/libcxx/docs/UsingLibcxx.rst
+++ b/libcxx/docs/UsingLibcxx.rst
@@ -147,35 +147,6 @@ 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



More information about the libcxx-commits mailing list