Added unittests for the -fsafe-stack and -fno-safe-stack options in clang and
-fstack-protector 4 option in clang-cc1.
http://reviews.llvm.org/D6095
Files:
include/clang/Basic/Attr.td
include/clang/Basic/AttrDocs.td
include/clang/Basic/LangOptions.def
include/clang/Basic/LangOptions.h
include/clang/Driver/Options.td
lib/CodeGen/CodeGenModule.cpp
lib/Driver/ToolChains.cpp
lib/Driver/Tools.cpp
lib/Frontend/CompilerInvocation.cpp
lib/Frontend/InitPreprocessor.cpp
lib/Sema/SemaDeclAttr.cpp
runtime/compiler-rt/Makefile
test/CodeGen/stack-protector.c
test/Driver/safestack.c
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.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/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/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<f_Group>,
HelpText<"Enable stack protectors for functions potentially vulnerable to stack smashing">;
+def fsafe_stack : Flag<["-"], "fsafe-stack">, Group<f_Group>,
+ HelpText<"Enable safe stack protection against stack-based memory corruption errors">;
+def fno_safe_stack : Flag<["-"], "fno-safe-stack">, Group<f_Group>,
+ HelpText<"Disable safe stack protection against stack-based memory corruption errors">;
def fstandalone_debug : Flag<["-"], "fstandalone-debug">, Group<f_Group>, Flags<[CC1Option]>,
HelpText<"Emit full debug info for all types used by the program">;
def fno_standalone_debug : Flag<["-"], "fno-standalone-debug">, Group<f_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<NoSafeStackAttr>())
+ 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<ScopedLockableAttr>(S, D, Attr);
break;
+ case AttributeList::AT_NoSafeStack:
+ handleSimpleAttribute<NoSafeStackAttr>(S, D, Attr);
+ break;
case AttributeList::AT_NoSanitizeAddress:
handleSimpleAttribute<NoSanitizeAddressAttr>(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/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"
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits