Index: docs/ControlFlowIntegrity.rst =================================================================== --- docs/ControlFlowIntegrity.rst +++ docs/ControlFlowIntegrity.rst @@ -20,8 +20,8 @@ allowing developers to enable them in release builds. To enable Clang's available CFI schemes, use the flag ``-fsanitize=cfi``. -As currently implemented, CFI relies on link-time optimization (LTO); the CFI -schemes imply ``-flto``, and the linker used must support LTO, for example +As currently implemented, CFI relies on link-time optimization (LTO); so it is +required to specify ``-flto``, and the linker used must support LTO, for example via the `gold plugin`_. To allow the checks to be implemented efficiently, the program must be structured such that certain object files are compiled with CFI enabled, and are statically linked into the program. This may Index: docs/UsersManual.rst =================================================================== --- docs/UsersManual.rst +++ docs/UsersManual.rst @@ -976,7 +976,7 @@ - ``-fsanitize=dataflow``: :doc:`DataFlowSanitizer`, a general data flow analysis. - ``-fsanitize=cfi``: :doc:`control flow integrity ` - checks. Implies ``-flto``. + checks. Requires ``-flto``. - ``-fsanitize=safe-stack``: :doc:`safe stack ` protection against stack-based memory corruption errors. @@ -991,13 +991,13 @@ - ``-fsanitize=cfi-cast-strict``: Enables :ref:`strict cast checks `. - ``-fsanitize=cfi-derived-cast``: Base-to-derived cast to the wrong - dynamic type. Implies ``-flto``. + dynamic type. Requires ``-flto``. - ``-fsanitize=cfi-unrelated-cast``: Cast from ``void*`` or another - unrelated type to the wrong dynamic type. Implies ``-flto``. + unrelated type to the wrong dynamic type. Requires ``-flto``. - ``-fsanitize=cfi-nvcall``: Non-virtual call via an object whose vptr is of - the wrong dynamic type. Implies ``-flto``. + the wrong dynamic type. Requires ``-flto``. - ``-fsanitize=cfi-vcall``: Virtual call via an object whose vptr is of the - wrong dynamic type. Implies ``-flto``. + wrong dynamic type. Requires ``-flto``. - ``-fsanitize=enum``: Load of a value of an enumerated type which is not in the range of representable values for that enumerated type. Index: include/clang/Driver/Driver.h =================================================================== --- include/clang/Driver/Driver.h +++ include/clang/Driver/Driver.h @@ -402,7 +402,7 @@ /// handle this action. bool ShouldUseClangCompiler(const JobAction &JA) const; - bool IsUsingLTO(const ToolChain &TC, const llvm::opt::ArgList &Args) const; + bool IsUsingLTO(const llvm::opt::ArgList &Args) const; private: /// \brief Retrieves a ToolChain for a particular target triple. Index: include/clang/Driver/SanitizerArgs.h =================================================================== --- include/clang/Driver/SanitizerArgs.h +++ include/clang/Driver/SanitizerArgs.h @@ -53,7 +53,6 @@ bool requiresPIE() const; bool needsUnwindTables() const; - bool needsLTO() const; bool linkCXXRuntimes() const { return LinkCXXRuntimes; } void addArgs(const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs) const; Index: lib/Driver/Driver.cpp =================================================================== --- lib/Driver/Driver.cpp +++ lib/Driver/Driver.cpp @@ -1362,7 +1362,7 @@ types::TY_LLVM_BC); } case phases::Backend: { - if (IsUsingLTO(TC, Args)) { + if (IsUsingLTO(Args)) { types::ID Output = Args.hasArg(options::OPT_S) ? types::TY_LTO_IR : types::TY_LTO_BC; return llvm::make_unique(std::move(Input), Output); @@ -1383,10 +1383,7 @@ llvm_unreachable("invalid phase in ConstructPhaseAction"); } -bool Driver::IsUsingLTO(const ToolChain &TC, const ArgList &Args) const { - if (TC.getSanitizerArgs().needsLTO()) - return true; - +bool Driver::IsUsingLTO(const ArgList &Args) const { if (Args.hasFlag(options::OPT_flto, options::OPT_fno_lto, false)) return true; Index: lib/Driver/SanitizerArgs.cpp =================================================================== --- lib/Driver/SanitizerArgs.cpp +++ lib/Driver/SanitizerArgs.cpp @@ -184,10 +184,6 @@ return Sanitizers.Mask & NeedsUnwindTables; } -bool SanitizerArgs::needsLTO() const { - return Sanitizers.Mask & NeedsLTO; -} - void SanitizerArgs::clear() { Sanitizers.clear(); RecoverableSanitizers.clear(); @@ -297,6 +293,12 @@ Kinds &= ~Vptr; } + // Check that LTO is enabled if we need it. + if ((Kinds & NeedsLTO) && !D.IsUsingLTO(Args)) { + D.Diag(diag::err_drv_argument_only_allowed_with) + << lastArgumentForMask(D, Args, Kinds & NeedsLTO) << "-flto"; + } + // Warn about incompatible groups of sanitizers. std::pair IncompatibleGroups[] = { std::make_pair(Address, Thread), std::make_pair(Address, Memory), Index: lib/Driver/Tools.cpp =================================================================== --- lib/Driver/Tools.cpp +++ lib/Driver/Tools.cpp @@ -6038,7 +6038,7 @@ Args.AddAllArgs(CmdArgs, options::OPT_Z_Flag); Args.AddAllArgs(CmdArgs, options::OPT_r); - if (D.IsUsingLTO(ToolChain, Args)) + if (D.IsUsingLTO(Args)) AddGoldPlugin(ToolChain, Args, CmdArgs); AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs); @@ -6189,8 +6189,7 @@ // If we are using LTO, then automatically create a temporary file path for // the linker to use, so that it's lifetime will extend past a possible // dsymutil step. - if (Version[0] >= 116 && D.IsUsingLTO(getToolChain(), Args) && - NeedsTempPath(Inputs)) { + if (Version[0] >= 116 && D.IsUsingLTO(Args) && NeedsTempPath(Inputs)) { const char *TmpPath = C.getArgs().MakeArgString( D.GetTemporaryPath("cc", types::getTypeTempSuffix(types::TY_Object))); C.addTempFile(TmpPath); @@ -7226,7 +7225,7 @@ Args.AddAllArgs(CmdArgs, options::OPT_Z_Flag); Args.AddAllArgs(CmdArgs, options::OPT_r); - if (D.IsUsingLTO(getToolChain(), Args)) + if (D.IsUsingLTO(Args)) AddGoldPlugin(ToolChain, Args, CmdArgs); bool NeedsSanitizerDeps = addSanitizerRuntimes(ToolChain, Args, CmdArgs); @@ -8086,7 +8085,7 @@ for (const auto &Path : Paths) CmdArgs.push_back(Args.MakeArgString(StringRef("-L") + Path)); - if (D.IsUsingLTO(getToolChain(), Args)) + if (D.IsUsingLTO(Args)) AddGoldPlugin(ToolChain, Args, CmdArgs); if (Args.hasArg(options::OPT_Z_Xlinker__no_demangle)) Index: test/Driver/fsanitize.c =================================================================== --- test/Driver/fsanitize.c +++ test/Driver/fsanitize.c @@ -190,17 +190,20 @@ // RUN: %clang -target x86_64-apple-darwin10 -fsanitize=function -fsanitize=undefined %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-FSAN-UBSAN-DARWIN // CHECK-FSAN-UBSAN-DARWIN: unsupported option '-fsanitize=function' for target 'x86_64-apple-darwin10' -// RUN: %clang -target x86_64-linux-gnu -fsanitize=cfi -c %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-CFI -// RUN: %clang -target x86_64-linux-gnu -fsanitize=cfi-derived-cast -c %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-CFI-DCAST -// RUN: %clang -target x86_64-linux-gnu -fsanitize=cfi-unrelated-cast -c %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-CFI-UCAST -// RUN: %clang -target x86_64-linux-gnu -fsanitize=cfi-nvcall -c %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-CFI-NVCALL -// RUN: %clang -target x86_64-linux-gnu -fsanitize=cfi-vcall -c %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-CFI-VCALL +// RUN: %clang -target x86_64-linux-gnu -fsanitize=cfi -flto -c %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-CFI +// RUN: %clang -target x86_64-linux-gnu -fsanitize=cfi-derived-cast -flto -c %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-CFI-DCAST +// RUN: %clang -target x86_64-linux-gnu -fsanitize=cfi-unrelated-cast -flto -c %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-CFI-UCAST +// RUN: %clang -target x86_64-linux-gnu -flto -fsanitize=cfi-nvcall -c %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-CFI-NVCALL +// RUN: %clang -target x86_64-linux-gnu -flto -fsanitize=cfi-vcall -c %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-CFI-VCALL // CHECK-CFI: -emit-llvm-bc{{.*}}-fsanitize=cfi-derived-cast,cfi-unrelated-cast,cfi-nvcall,cfi-vcall // CHECK-CFI-DCAST: -emit-llvm-bc{{.*}}-fsanitize=cfi-derived-cast // CHECK-CFI-UCAST: -emit-llvm-bc{{.*}}-fsanitize=cfi-unrelated-cast // CHECK-CFI-NVCALL: -emit-llvm-bc{{.*}}-fsanitize=cfi-nvcall // CHECK-CFI-VCALL: -emit-llvm-bc{{.*}}-fsanitize=cfi-vcall +// RUN: %clang -target x86_64-linux-gnu -flto -fsanitize=cfi-derived-cast -fno-lto -c %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-CFI-NOLTO +// CHECK-CFI-NOLTO: '-fsanitize=cfi-derived-cast' only allowed with '-flto' + // RUN: %clang -target x86_64-linux-gnu -fsanitize-trap=address -c %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-ASAN-TRAP // CHECK-ASAN-TRAP: error: unsupported argument 'address' to option '-fsanitize-trap'