Index: include/clang/Basic/Attr.td =================================================================== --- include/clang/Basic/Attr.td +++ include/clang/Basic/Attr.td @@ -1317,6 +1317,13 @@ let Documentation = [Undocumented]; } +// Attribute to disable SafeStack (or equivalent) instrumentation. +def NoSafeStack : InheritableAttr { + let Spellings = [GCC<"no_safe_stack">]; + let Subjects = SubjectList<[Function], ErrorDiag>; + let Documentation = [NoSafeStackDocs]; +} + // Attribute to disable AddressSanitizer (or equivalent) checks. def NoSanitizeAddress : InheritableAttr { let Spellings = [GCC<"no_address_safety_analysis">, Index: include/clang/Basic/AttrDocs.td =================================================================== --- include/clang/Basic/AttrDocs.td +++ include/clang/Basic/AttrDocs.td @@ -860,6 +860,17 @@ }]; } +def NoSafeStackDocs : Documentation { + let Category = DocCatFunction; + let Content = [{ +Use ``__attribute__((no_safe_stack))`` on a function declaration to specify +that the safe stack instrumentation should not be applied to that function, +even if enabled globally (see -fsafe-stack flag). This attribute may be +required for functions that make assumptions about the exact layout of their +stack frames. + }]; +} + def NoSanitizeAddressDocs : Documentation { let Category = DocCatFunction; // This function has multiple distinct spellings, and so it requires a custom Index: include/clang/Basic/LangOptions.h =================================================================== --- include/clang/Basic/LangOptions.h +++ include/clang/Basic/LangOptions.h @@ -66,7 +66,7 @@ typedef clang::Visibility Visibility; enum GCMode { NonGC, GCOnly, HybridGC }; - enum StackProtectorMode { SSPOff, SSPOn, SSPStrong, SSPReq }; + enum StackProtectorMode { SSPOff, SSPOn, SSPStrong, SSPReq, SSPSafeStack }; enum SignedOverflowBehaviorTy { SOB_Undefined, // Default C standard behavior. Index: include/clang/Basic/LangOptions.def =================================================================== --- include/clang/Basic/LangOptions.def +++ include/clang/Basic/LangOptions.def @@ -192,7 +192,7 @@ "value symbol visibility") ENUM_LANGOPT(TypeVisibilityMode, Visibility, 3, DefaultVisibility, "type symbol visibility") -ENUM_LANGOPT(StackProtector, StackProtectorMode, 2, SSPOff, +ENUM_LANGOPT(StackProtector, StackProtectorMode, 3, SSPOff, "stack protector mode") ENUM_LANGOPT(SignedOverflowBehavior, SignedOverflowBehaviorTy, 2, SOB_Undefined, "signed integer overflow handling") Index: include/clang/Driver/Options.td =================================================================== --- include/clang/Driver/Options.td +++ include/clang/Driver/Options.td @@ -864,6 +864,10 @@ HelpText<"Use a strong heuristic to apply stack protectors to functions">; def fstack_protector : Flag<["-"], "fstack-protector">, Group, HelpText<"Enable stack protectors for functions potentially vulnerable to stack smashing">; +def fsafe_stack : Flag<["-"], "fsafe-stack">, Group, + HelpText<"Enable safe stack protection against stack-based memory corruption errors">; +def fno_safe_stack : Flag<["-"], "fno-safe-stack">, Group, + HelpText<"Disable safe stack protection against stack-based memory corruption errors">; def fstandalone_debug : Flag<["-"], "fstandalone-debug">, Group, Flags<[CC1Option]>, HelpText<"Emit full debug info for all types used by the program">; def fno_standalone_debug : Flag<["-"], "fno-standalone-debug">, Group, Flags<[CC1Option]>, Index: lib/CodeGen/CodeGenModule.cpp =================================================================== --- lib/CodeGen/CodeGenModule.cpp +++ lib/CodeGen/CodeGenModule.cpp @@ -738,6 +738,9 @@ B.addAttribute(llvm::Attribute::StackProtectStrong); else if (LangOpts.getStackProtector() == LangOptions::SSPReq) B.addAttribute(llvm::Attribute::StackProtectReq); + else if (LangOpts.getStackProtector() == LangOptions::SSPSafeStack) + if (!D->hasAttr()) + B.addAttribute(llvm::Attribute::SafeStack); // Add sanitizer attributes if function is not blacklisted. if (!isInSanitizerBlacklist(F, D->getLocation())) { Index: lib/Driver/ToolChains.cpp =================================================================== --- lib/Driver/ToolChains.cpp +++ lib/Driver/ToolChains.cpp @@ -10,6 +10,7 @@ #include "ToolChains.h" #include "clang/Basic/ObjCRuntime.h" #include "clang/Basic/Version.h" +#include "clang/Basic/LangOptions.h" #include "clang/Config/config.h" // for GCC_INSTALL_PREFIX #include "clang/Driver/Compilation.h" #include "clang/Driver/Driver.h" Index: lib/Driver/Tools.cpp =================================================================== --- lib/Driver/Tools.cpp +++ lib/Driver/Tools.cpp @@ -2172,6 +2172,30 @@ CmdArgs.push_back(Args.MakeArgString(LibProfile)); } +static void addSafeStackRT( + const ToolChain &TC, const ArgList &Args, ArgStringList &CmdArgs) { + if (!Args.hasFlag(options::OPT_fsafe_stack, + options::OPT_fno_safe_stack, false)) + return; + + const char *LibBaseName = "libclang_rt.safestack-"; + SmallString<128> LibName = getCompilerRTLibDir(TC); + llvm::sys::path::append(LibName, + Twine(LibBaseName) + getArchNameForCompilerRTLib(TC) + ".a"); + + CmdArgs.push_back(Args.MakeArgString(LibName)); + + // Safestack runtime requires dl on Linux + if (TC.getTriple().isOSLinux()) + CmdArgs.push_back("-ldl"); + + // We need to ensure that the safe stack init function from the safestack + // runtime library is linked in, even though it might not be referenced by + // any code in the module before LTO optimizations are applied. + CmdArgs.push_back("-u"); + CmdArgs.push_back("__llvm__safestack_init"); +} + static SmallString<128> getSanitizerRTLibName(const ToolChain &TC, StringRef Sanitizer, bool Shared) { @@ -3675,7 +3699,14 @@ // -stack-protector=0 is default. unsigned StackProtectorLevel = 0; - if (Arg *A = Args.getLastArg(options::OPT_fno_stack_protector, + if (Args.hasFlag(options::OPT_fsafe_stack, + options::OPT_fno_safe_stack, false)) { + StackProtectorLevel = LangOptions::SSPSafeStack; + Args.ClaimAllArgs(options::OPT_fno_stack_protector); + Args.ClaimAllArgs(options::OPT_fstack_protector_all); + Args.ClaimAllArgs(options::OPT_fstack_protector_strong); + Args.ClaimAllArgs(options::OPT_fstack_protector); + } else if (Arg *A = Args.getLastArg(options::OPT_fno_stack_protector, options::OPT_fstack_protector_all, options::OPT_fstack_protector_strong, options::OPT_fstack_protector)) { @@ -5843,6 +5874,21 @@ !Args.hasArg(options::OPT_nostartfiles)) getMachOToolChain().addStartObjectFileArgs(Args, CmdArgs); + // SafeStack requires its own runtime libraries + // These libraries should be linked first, to make sure the + // __llvm__safestack_init constructor executes before everything else + if (Args.hasFlag(options::OPT_fsafe_stack, + options::OPT_fno_safe_stack, false)) { + getMachOToolChain().AddLinkRuntimeLib(Args, CmdArgs, + "libclang_rt.safestack_osx.a"); + + // We need to ensure that the safe stack init function from the safestack + // runtime library is linked in, even though it might not be referenced by + // any code in the module before LTO optimizations are applied. + CmdArgs.push_back("-u"); + CmdArgs.push_back("___llvm__safestack_init"); + } + Args.AddAllArgs(CmdArgs, options::OPT_L); LibOpenMP UsedOpenMPLib = LibUnknown; @@ -6092,6 +6138,8 @@ CmdArgs.push_back(Args.MakeArgString("-L" + GCCLibPath)); + addSafeStackRT(getToolChain(), Args, CmdArgs); + Args.AddAllArgs(CmdArgs, options::OPT_L); Args.AddAllArgs(CmdArgs, options::OPT_T_Group); Args.AddAllArgs(CmdArgs, options::OPT_e); @@ -6638,6 +6686,8 @@ CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(crtbegin))); } + addSafeStackRT(getToolChain(), Args, CmdArgs); + Args.AddAllArgs(CmdArgs, options::OPT_L); const ToolChain::path_list &Paths = ToolChain.getFilePaths(); for (const auto &Path : Paths) @@ -6932,6 +6982,8 @@ } } + addSafeStackRT(getToolChain(), Args, CmdArgs); + Args.AddAllArgs(CmdArgs, options::OPT_L); Args.AddAllArgs(CmdArgs, options::OPT_T_Group); Args.AddAllArgs(CmdArgs, options::OPT_e); @@ -7471,6 +7523,8 @@ ToolChain.AddFastMathRuntimeIfAvailable(Args, CmdArgs); } + addSafeStackRT(getToolChain(), Args, CmdArgs); + Args.AddAllArgs(CmdArgs, options::OPT_L); Args.AddAllArgs(CmdArgs, options::OPT_u); @@ -7613,6 +7667,8 @@ CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath("crtn.o"))); } + addSafeStackRT(getToolChain(), Args, CmdArgs); + Args.AddAllArgs(CmdArgs, options::OPT_L); Args.AddAllArgs(CmdArgs, options::OPT_T_Group); Args.AddAllArgs(CmdArgs, options::OPT_e); @@ -7738,6 +7794,8 @@ getToolChain().GetFilePath("crtbegin.o"))); } + addSafeStackRT(getToolChain(), Args, CmdArgs); + Args.AddAllArgs(CmdArgs, options::OPT_L); Args.AddAllArgs(CmdArgs, options::OPT_T_Group); Args.AddAllArgs(CmdArgs, options::OPT_e); Index: lib/Frontend/CompilerInvocation.cpp =================================================================== --- lib/Frontend/CompilerInvocation.cpp +++ lib/Frontend/CompilerInvocation.cpp @@ -1606,6 +1606,7 @@ case 1: Opts.setStackProtector(LangOptions::SSPOn); break; case 2: Opts.setStackProtector(LangOptions::SSPStrong); break; case 3: Opts.setStackProtector(LangOptions::SSPReq); break; + case 4: Opts.setStackProtector(LangOptions::SSPSafeStack); break; } // Parse -fsanitize= arguments. Index: lib/Frontend/InitPreprocessor.cpp =================================================================== --- lib/Frontend/InitPreprocessor.cpp +++ lib/Frontend/InitPreprocessor.cpp @@ -826,6 +826,8 @@ Builder.defineMacro("__SSP_STRONG__", "2"); else if (LangOpts.getStackProtector() == LangOptions::SSPReq) Builder.defineMacro("__SSP_ALL__", "3"); + else if (LangOpts.getStackProtector() == LangOptions::SSPSafeStack) + Builder.defineMacro("__SAFESTACK__", "4"); if (FEOpts.ProgramAction == frontend::RewriteObjC) Builder.defineMacro("__weak", "__attribute__((objc_gc(weak)))"); Index: lib/Sema/SemaDeclAttr.cpp =================================================================== --- lib/Sema/SemaDeclAttr.cpp +++ lib/Sema/SemaDeclAttr.cpp @@ -4593,6 +4593,9 @@ case AttributeList::AT_ScopedLockable: handleSimpleAttribute(S, D, Attr); break; + case AttributeList::AT_NoSafeStack: + handleSimpleAttribute(S, D, Attr); + break; case AttributeList::AT_NoSanitizeAddress: handleSimpleAttribute(S, D, Attr); break; Index: runtime/compiler-rt/Makefile =================================================================== --- runtime/compiler-rt/Makefile +++ runtime/compiler-rt/Makefile @@ -83,7 +83,7 @@ eprintf.a 10.4.a osx.a ios.a cc_kext.a cc_kext_ios5.a \ asan_osx_dynamic.dylib \ profile_osx.a profile_ios.a \ - ubsan_osx.a + ubsan_osx.a safestack_osx.a RuntimeLibrary.macho_embedded.Configs := \ hard_static.a hard_pic.a @@ -127,7 +127,7 @@ # We try to build 32-bit runtimes both on 32-bit hosts and 64-bit hosts. Runtime32BitConfigs = \ builtins-i386.a profile-i386.a san-i386.a asan-i386.a asan_cxx-i386.a \ - ubsan-i386.a ubsan_cxx-i386.a + ubsan-i386.a ubsan_cxx-i386.a safestack-i386.a # We currently only try to generate runtime libraries on x86. ifeq ($(ARCH),x86) @@ -138,7 +138,7 @@ RuntimeLibrary.linux.Configs += \ builtins-x86_64.a profile-x86_64.a san-x86_64.a asan-x86_64.a \ asan_cxx-x86_64.a tsan-x86_64.a msan-x86_64.a ubsan-x86_64.a \ - ubsan_cxx-x86_64.a dfsan-x86_64.a lsan-x86_64.a + ubsan_cxx-x86_64.a dfsan-x86_64.a lsan-x86_64.a safestack-x86_64.a # We need to build 32-bit ASan/UBsan libraries on 64-bit platform, and add them # to the list of runtime libraries to make # "clang -fsanitize=(address|undefined) -m32" work. Index: test/CodeGen/safestack-attr.cpp =================================================================== --- /dev/null +++ test/CodeGen/safestack-attr.cpp @@ -0,0 +1,6 @@ +// RUN: %clang_cc1 -triple x86_64-linux-unknown -emit-llvm -o - %s -stack-protector 4 | FileCheck -check-prefix=SP %s + +__attribute__((no_safe_stack)) +int foo(int *a) { return *a; } + +// SP-NOT: attributes #{{.*}} = { nounwind safestack{{.*}} } Index: test/CodeGen/stack-protector.c =================================================================== --- test/CodeGen/stack-protector.c +++ test/CodeGen/stack-protector.c @@ -6,6 +6,8 @@ // SSPSTRONG: define void @test1(i8* %msg) #0 { // RUN: %clang_cc1 -emit-llvm -o - %s -stack-protector 3 | FileCheck -check-prefix=SSPREQ %s // SSPREQ: define void @test1(i8* %msg) #0 { +// RUN: %clang_cc1 -emit-llvm -o - %s -stack-protector 4 | FileCheck -check-prefix=SAFESTACK %s +// SAFESTACK: define void @test1(i8* %msg) #0 { typedef __SIZE_TYPE__ size_t; @@ -26,3 +28,5 @@ // SSPSTRONG: attributes #{{.*}} = { nounwind sspstrong{{.*}} } // SSPREQ: attributes #{{.*}} = { nounwind sspreq{{.*}} } + +// SAFESTACK: attributes #{{.*}} = { nounwind safestack{{.*}} } Index: test/Driver/safestack.c =================================================================== --- /dev/null +++ test/Driver/safestack.c @@ -0,0 +1,6 @@ +// RUN: %clang -fno-safe-stack -### %s 2>&1 | FileCheck %s -check-prefix=NOSP +// NOSP-NOT: "-stack-protector" "4" + +// RUN: %clang -fsafe-stack -### %s 2>&1 | FileCheck %s -check-prefix=SP +// RUN: %clang -fsanatizer=address -fsafe-stack -### %s 2>&1 | FileCheck %s -check-prefix=SP +// SP: "-stack-protector" "4" Index: test/SemaCXX/attr-no-safestack.cpp =================================================================== --- /dev/null +++ test/SemaCXX/attr-no-safestack.cpp @@ -0,0 +1,37 @@ +// RUN: %clang_cc1 -fsyntax-only -verify %s + +#define NO_SAFE_STACK __attribute__((no_safe_stack)) + +#if !__has_attribute(no_safe_stack) +#error "Should support no_safe_stack" +#endif + +void nosp_fun() NO_SAFE_STACK; + +void nosp_fun_args() __attribute__((no_safe_stack(1))); // \ + // expected-error {{'no_safe_stack' attribute takes no arguments}} + +int nosp_testfn(int y) NO_SAFE_STACK; + +int nosp_testfn(int y) { + int x NO_SAFE_STACK = y; // \ + // expected-error {{'no_safe_stack' attribute only applies to functions}} + return x; +} + +int nosp_test_var NO_SAFE_STACK; // \ + // expected-error {{'no_safe_stack' attribute only applies to functions}} + +class NoSPFoo { + private: + int test_field NO_SAFE_STACK; // \ + // expected-error {{'no_safe_stack' attribute only applies to functions}} + void test_method() NO_SAFE_STACK; +}; + +class NO_SAFE_STACK NoSPTestClass { // \ + // expected-error {{'no_safe_stack' attribute only applies to functions}} +}; + +void nosp_fun_params(int lvar NO_SAFE_STACK); // \ + // expected-error {{'no_safe_stack' attribute only applies to functions}}