[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