diff --git a/clang/docs/UsersManual.rst b/clang/docs/UsersManual.rst index 881d903d91a7e..511953e25ced7 100644 --- a/clang/docs/UsersManual.rst +++ b/clang/docs/UsersManual.rst @@ -3422,6 +3422,17 @@ Controlling implementation limits Sets the limit for iterative calls to 'operator->' functions to N. The default is 256. +Enabling standard library hardening +----------------------------------- + +.. option:: -fstdlib-hardening=[none, fast, extensive, debug] + + Enables `standard library hardening `. + When the option is used, clang sets macro ``_LIBCPP_HARDENING_MODE`` to + ``_LIBCPP_HARDENING_MODE_{NONE,FAST,EXTENSIVE,DEBUG}`` based on the hardening + mode chosen by the user. This feature is currently available only when libc++ + is used. + .. _objc: Objective-C Language Features diff --git a/clang/include/clang/Basic/DiagnosticDriverKinds.td b/clang/include/clang/Basic/DiagnosticDriverKinds.td index 090b169a0e724..a53bad560b3ae 100644 --- a/clang/include/clang/Basic/DiagnosticDriverKinds.td +++ b/clang/include/clang/Basic/DiagnosticDriverKinds.td @@ -275,6 +275,9 @@ def warn_drv_unknown_argument_clang_cl_with_suggestion : Warning< InGroup; 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; diff --git a/clang/include/clang/Basic/LangOptions.def b/clang/include/clang/Basic/LangOptions.def index 04ebffbcba69d..6a84259193290 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(StdlibHardeningMode, StdlibHardeningModeKind, 3, STDLIB_HARDENING_MODE_NOT_SPECIFIED, "standard library 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 9f986fce2d441..e9ef9643843ff 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 StdlibHardeningModeKind { + STDLIB_HARDENING_MODE_NOT_SPECIFIED, + STDLIB_HARDENING_MODE_NONE, + STDLIB_HARDENING_MODE_FAST, + STDLIB_HARDENING_MODE_EXTENSIVE, + STDLIB_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 d2e6c3ff721c2..b3e651505fa45 100644 --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -7730,6 +7730,19 @@ def source_date_epoch : Separate<["-"], "source-date-epoch">, } // let Visibility = [CC1Option] +def stdlib_hardening_EQ : Joined<["-"], "fstdlib-hardening=">, + Values<"none,fast,extensive,debug">, + NormalizedValues<["STDLIB_HARDENING_MODE_NONE", "STDLIB_HARDENING_MODE_FAST", "STDLIB_HARDENING_MODE_EXTENSIVE", "STDLIB_HARDENING_MODE_DEBUG"]>, + Visibility<[ClangOption, CC1Option]>, + HelpText<"standard library hardening mode">, + NormalizedValuesScope<"LangOptions">, + DocBrief<"Enable libc++ harderning:" + " none (the default mode that doesn’t compromise any runtime performance to check for undefined behavior) |" + " fast (contains a minimal set of low-overhead checks deemed security-critical) |" + " extensive (extends the hardened mode with additional low-overhead checks that are not security-critical) |" + " debug (extends the extensive mode with checks that might impose significant overhead, for example, might change the complexity of algorithms)">, + MarshallingInfoEnum, "STDLIB_HARDENING_MODE_NOT_SPECIFIED">; + //===----------------------------------------------------------------------===// // CUDA Options //===----------------------------------------------------------------------===// diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp index fead2e884030e..560793958455c 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 d83128adb511e..4384a955def08 100644 --- a/clang/lib/Frontend/InitPreprocessor.cpp +++ b/clang/lib/Frontend/InitPreprocessor.cpp @@ -851,6 +851,28 @@ static void InitializePredefinedMacros(const TargetInfo &TI, Twine(getClangFullCPPVersion()) + "\""); // Initialize language-specific preprocessor defines. + if (LangOpts.getStdlibHardeningMode()) { + const char *StdlibHardeningStr; + + switch (LangOpts.getStdlibHardeningMode()) { + case clang::LangOptions::STDLIB_HARDENING_MODE_NOT_SPECIFIED: + llvm_unreachable("Unexpected libc++ hardening mode value"); + case clang::LangOptions::STDLIB_HARDENING_MODE_NONE: + StdlibHardeningStr = "_LIBCPP_HARDENING_MODE_NONE"; + break; + case clang::LangOptions::STDLIB_HARDENING_MODE_FAST: + StdlibHardeningStr = "_LIBCPP_HARDENING_MODE_FAST"; + break; + case clang::LangOptions::STDLIB_HARDENING_MODE_EXTENSIVE: + StdlibHardeningStr = "_LIBCPP_HARDENING_MODE_EXTENSIVE"; + break; + case clang::LangOptions::STDLIB_HARDENING_MODE_DEBUG: + StdlibHardeningStr = "_LIBCPP_HARDENING_MODE_DEBUG"; + break; + } + + Builder.defineMacro("_LIBCPP_HARDENING_MODE", StdlibHardeningStr); + } // 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 0000000000000..db30dfc2d5d07 --- /dev/null +++ b/clang/test/Driver/libcxx-hardening.cpp @@ -0,0 +1,16 @@ +// 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=NONE %s +// RUN: %clang -E -dM -x c++ -fstdlib-hardening=fast -stdlib=libc++ %s | FileCheck -check-prefix=FAST %s +// RUN: %clang -E -dM -x c++ -fstdlib-hardening=extensive -stdlib=libc++ %s | FileCheck -check-prefix=EXTENSIVE %s +// RUN: %clang -E -dM -x c++ -fstdlib-hardening=debug -stdlib=libc++ %s | FileCheck -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 + +// ERROR: libc++ hardening is available only when libc++ is used