[clang] Add option -fstdlib-hardening= (PR #78763)

Akira Hatanaka via cfe-commits cfe-commits at lists.llvm.org
Fri Jan 19 11:12:59 PST 2024


https://github.com/ahatanak created https://github.com/llvm/llvm-project/pull/78763

The option allows users to enable libc++ hardening, which was discussed in the following RFC:

https://discourse.llvm.org/t/rfc-hardening-in-libc/73925

Users specifiy the hardening mode by passing one of the following values as the argument to the option: none, fast, extensive, or debug.

When the option is used, clang defines a macro for each of the hardening modes (_LIBCPP_HARDENING_MODE_{NONE,FAST,EXTENSIVE,DEBUG}) and sets macro _LIBCPP_HARDENING_MODE_ based on the hardening mode the user chose.

It's an error to use the option if the stdlib used isn't libc++ or clang isn't compiling in C++ mode.

>From 0d68286bd8b7206c5045062f65ccaf1c3fb54714 Mon Sep 17 00:00:00 2001
From: Akira Hatanaka <ahatanak at gmail.com>
Date: Thu, 18 Jan 2024 16:20:41 -0800
Subject: [PATCH] Add option -fstdlib-hardening=

The option allows users to enable libc++ hardening, which was discussed
in the following RFC:

https://discourse.llvm.org/t/rfc-hardening-in-libc/73925

Users specifiy the hardening mode by passing one of the following values
as the argument to the option: none, fast, extensive, or debug.

When the option is used, clang defines a macro for each of the hardening
modes (_LIBCPP_HARDENING_MODE_{NONE,FAST,EXTENSIVE,DEBUG}) and sets
macro _LIBCPP_HARDENING_MODE_ based on the hardening mode the user
chose.

It's an error to use the option if the stdlib used isn't libc++ or
clang isn't compiling in C++ mode.
---
 .../clang/Basic/DiagnosticDriverKinds.td      |  2 ++
 clang/include/clang/Basic/LangOptions.def     |  1 +
 clang/include/clang/Basic/LangOptions.h       |  8 ++++++
 clang/include/clang/Driver/Options.td         |  8 ++++++
 clang/lib/Driver/ToolChains/Clang.cpp         |  8 ++++++
 clang/lib/Frontend/InitPreprocessor.cpp       | 27 +++++++++++++++++++
 clang/test/Driver/libcxx-hardening.cpp        | 21 +++++++++++++++
 7 files changed, 75 insertions(+)
 create mode 100644 clang/test/Driver/libcxx-hardening.cpp

diff --git a/clang/include/clang/Basic/DiagnosticDriverKinds.td b/clang/include/clang/Basic/DiagnosticDriverKinds.td
index 090b169a0e72408..2369ddc8a80ead3 100644
--- a/clang/include/clang/Basic/DiagnosticDriverKinds.td
+++ b/clang/include/clang/Basic/DiagnosticDriverKinds.td
@@ -275,6 +275,8 @@ def warn_drv_unknown_argument_clang_cl_with_suggestion : Warning<
   InGroup<UnknownArgument>;
 def err_drv_unknown_target_triple : Error<"unknown target triple '%0'">;
 
+def err_drv_stdlib_hardening_unavailable : Error<"libc++ hardening is available only when libc++ is used">;
+
 def warn_drv_ycyu_different_arg_clang_cl : Warning<
   "support for '/Yc' and '/Yu' with different filenames not implemented yet; flags ignored">,
   InGroup<ClangClPch>;
diff --git a/clang/include/clang/Basic/LangOptions.def b/clang/include/clang/Basic/LangOptions.def
index 04ebffbcba69dbf..0db8ff04ad0d52d 100644
--- a/clang/include/clang/Basic/LangOptions.def
+++ b/clang/include/clang/Basic/LangOptions.def
@@ -281,6 +281,7 @@ LANGOPT(OffloadingNewDriver, 1, 0, "use the new driver for generating offloading
 LANGOPT(SYCLIsDevice      , 1, 0, "Generate code for SYCL device")
 LANGOPT(SYCLIsHost        , 1, 0, "SYCL host compilation")
 ENUM_LANGOPT(SYCLVersion  , SYCLMajorVersion, 2, SYCL_None, "Version of the SYCL standard used")
+ENUM_LANGOPT(LibcxxHardeningMode, LibcxxHardeningModeKind, 3, LIBCPP_HARDENING_MODE_NOT_SPECIFIED, "libc++ harderning mode")
 
 LANGOPT(HIPUseNewLaunchAPI, 1, 0, "Use new kernel launching API for HIP")
 LANGOPT(OffloadUniformBlock, 1, 0, "Assume that kernels are launched with uniform block sizes (default true for CUDA/HIP and false otherwise)")
diff --git a/clang/include/clang/Basic/LangOptions.h b/clang/include/clang/Basic/LangOptions.h
index 9f986fce2d44188..62e70a5cffafd61 100644
--- a/clang/include/clang/Basic/LangOptions.h
+++ b/clang/include/clang/Basic/LangOptions.h
@@ -174,6 +174,14 @@ class LangOptions : public LangOptionsBase {
     HLSL_202x = 2029,
   };
 
+  enum LibcxxHardeningModeKind {
+    LIBCPP_HARDENING_MODE_NOT_SPECIFIED,
+    LIBCPP_HARDENING_MODE_NONE,
+    LIBCPP_HARDENING_MODE_FAST,
+    LIBCPP_HARDENING_MODE_EXTENSIVE,
+    LIBCPP_HARDENING_MODE_DEBUG
+  };
+
   /// Clang versions with different platform ABI conformance.
   enum class ClangABI {
     /// Attempt to be ABI-compatible with code generated by Clang 3.8.x
diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td
index d2e6c3ff721c27e..7ce38f88d156441 100644
--- a/clang/include/clang/Driver/Options.td
+++ b/clang/include/clang/Driver/Options.td
@@ -7730,6 +7730,14 @@ def source_date_epoch : Separate<["-"], "source-date-epoch">,
 
 } // let Visibility = [CC1Option]
 
+def stdlib_hardening_EQ : Joined<["-"], "fstdlib-hardening=">,
+  Values<"none,fast,extensive,debug">,
+  NormalizedValues<["LIBCPP_HARDENING_MODE_NONE", "LIBCPP_HARDENING_MODE_FAST", "LIBCPP_HARDENING_MODE_EXTENSIVE", "LIBCPP_HARDENING_MODE_DEBUG"]>,
+  Visibility<[ClangOption, CC1Option]>,
+  HelpText<"libc++ hardening mode">,
+  NormalizedValuesScope<"LangOptions">,
+  MarshallingInfoEnum<LangOpts<"LibcxxHardeningMode">, "LIBCPP_HARDENING_MODE_NOT_SPECIFIED">;
+
 //===----------------------------------------------------------------------===//
 // CUDA Options
 //===----------------------------------------------------------------------===//
diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp
index fead2e884030e21..560793958455ced 100644
--- a/clang/lib/Driver/ToolChains/Clang.cpp
+++ b/clang/lib/Driver/ToolChains/Clang.cpp
@@ -1256,6 +1256,14 @@ void Clang::AddPreprocessingOptions(Compilation &C, const JobAction &JA,
   if (Arg *A = Args.getLastArg(options::OPT_I_))
     D.Diag(diag::err_drv_I_dash_not_supported) << A->getAsString(Args);
 
+  if (Arg *A = Args.getLastArg(options::OPT_stdlib_hardening_EQ)) {
+    if (types::isCXX(Inputs[0].getType()) &&
+        getToolChain().GetCXXStdlibType(Args) == ToolChain::CST_Libcxx)
+      A->render(Args, CmdArgs);
+    else
+      D.Diag(diag::err_drv_stdlib_hardening_unavailable);
+  }
+
   // If we have a --sysroot, and don't have an explicit -isysroot flag, add an
   // -isysroot to the CC1 invocation.
   StringRef sysroot = C.getSysRoot();
diff --git a/clang/lib/Frontend/InitPreprocessor.cpp b/clang/lib/Frontend/InitPreprocessor.cpp
index d83128adb511ef4..fab4894dee4a219 100644
--- a/clang/lib/Frontend/InitPreprocessor.cpp
+++ b/clang/lib/Frontend/InitPreprocessor.cpp
@@ -851,6 +851,33 @@ static void InitializePredefinedMacros(const TargetInfo &TI,
                       Twine(getClangFullCPPVersion()) + "\"");
 
   // Initialize language-specific preprocessor defines.
+  if (LangOpts.getLibcxxHardeningMode()) {
+    const char *LibcxxHardeningStr;
+
+    Builder.defineMacro("_LIBCPP_HARDENING_MODE_NONE", "0");
+    Builder.defineMacro("_LIBCPP_HARDENING_MODE_FAST", "1");
+    Builder.defineMacro("_LIBCPP_HARDENING_MODE_EXTENSIVE", "2");
+    Builder.defineMacro("_LIBCPP_HARDENING_MODE_DEBUG", "3");
+
+    switch (LangOpts.getLibcxxHardeningMode()) {
+    case clang::LangOptions::LIBCPP_HARDENING_MODE_NOT_SPECIFIED:
+      llvm_unreachable("Unexpected libc++ hardening mode value");
+    case clang::LangOptions::LIBCPP_HARDENING_MODE_NONE:
+      LibcxxHardeningStr = "_LIBCPP_HARDENING_MODE_NONE";
+      break;
+    case clang::LangOptions::LIBCPP_HARDENING_MODE_FAST:
+      LibcxxHardeningStr = "_LIBCPP_HARDENING_MODE_FAST";
+      break;
+    case clang::LangOptions::LIBCPP_HARDENING_MODE_EXTENSIVE:
+      LibcxxHardeningStr = "_LIBCPP_HARDENING_MODE_EXTENSIVE";
+      break;
+    case clang::LangOptions::LIBCPP_HARDENING_MODE_DEBUG:
+      LibcxxHardeningStr = "_LIBCPP_HARDENING_MODE_DEBUG";
+      break;
+    }
+
+    Builder.defineMacro("_LIBCPP_HARDENING_MODE", LibcxxHardeningStr);
+  }
 
   // Standard conforming mode?
   if (!LangOpts.GNUMode && !LangOpts.MSVCCompat)
diff --git a/clang/test/Driver/libcxx-hardening.cpp b/clang/test/Driver/libcxx-hardening.cpp
new file mode 100644
index 000000000000000..7400c986048de6c
--- /dev/null
+++ b/clang/test/Driver/libcxx-hardening.cpp
@@ -0,0 +1,21 @@
+// RUN: %clang -E -dM -x c++ %s | FileCheck -check-prefix=UNSPECIFIED %s
+// RUN: %clang -E -dM -x c++ -fstdlib-hardening=none -stdlib=libc++ %s | FileCheck -check-prefix=CHECK -check-prefix=NONE %s
+// RUN: %clang -E -dM -x c++ -fstdlib-hardening=fast -stdlib=libc++ %s | FileCheck -check-prefix=CHECK -check-prefix=FAST %s
+// RUN: %clang -E -dM -x c++ -fstdlib-hardening=extensive -stdlib=libc++ %s | FileCheck -check-prefix=CHECK -check-prefix=EXTENSIVE %s
+// RUN: %clang -E -dM -x c++ -fstdlib-hardening=debug -stdlib=libc++ %s | FileCheck -check-prefix=CHECK -check-prefix=DEBUG %s
+// RUN: not %clang -x c++ -fstdlib-hardening=debug -stdlib=libstdc++ %s 2>&1 | FileCheck -check-prefix=ERROR %s
+// RUN: not %clang -x c -fstdlib-hardening=debug %s 2>&1 | FileCheck -check-prefix=ERROR %s
+
+// UNSPECIFIED-NOT: _LIBCPP_HARDENING_MODE
+
+// NONE: #define _LIBCPP_HARDENING_MODE _LIBCPP_HARDENING_MODE_NONE
+// FAST: #define _LIBCPP_HARDENING_MODE _LIBCPP_HARDENING_MODE_FAST
+// EXTENSIVE: #define _LIBCPP_HARDENING_MODE _LIBCPP_HARDENING_MODE_EXTENSIVE
+// DEBUG: #define _LIBCPP_HARDENING_MODE _LIBCPP_HARDENING_MODE_DEBUG
+
+// CHECK: #define _LIBCPP_HARDENING_MODE_DEBUG 3
+// CHECK: #define _LIBCPP_HARDENING_MODE_EXTENSIVE 2
+// CHECK: #define _LIBCPP_HARDENING_MODE_FAST 1
+// CHECK: #define _LIBCPP_HARDENING_MODE_NONE 0
+
+// ERROR: libc++ hardening is available only when libc++ is used



More information about the cfe-commits mailing list