summaryrefslogtreecommitdiffstats
path: root/clang/lib/CodeGen
diff options
context:
space:
mode:
authorJulian Lettner <jlettner@apple.com>2019-01-30 23:42:13 +0000
committerJulian Lettner <jlettner@apple.com>2019-01-30 23:42:13 +0000
commit8280c1e23ed998a439f26b7637d2dc82ee2f5d3e (patch)
treee73ae60660e8546d560ee7abb472149c041bd652 /clang/lib/CodeGen
parentbe589423d8ea24370bb087a2a05f75100d1be76d (diff)
downloadbcm5719-llvm-8280c1e23ed998a439f26b7637d2dc82ee2f5d3e.tar.gz
bcm5719-llvm-8280c1e23ed998a439f26b7637d2dc82ee2f5d3e.zip
[Sanitizers] UBSan unreachable incompatible with ASan in the presence of `noreturn` calls
Summary: UBSan wants to detect when unreachable code is actually reached, so it adds instrumentation before every unreachable instruction. However, the optimizer will remove code after calls to functions marked with noreturn. To avoid this UBSan removes noreturn from both the call instruction as well as from the function itself. Unfortunately, ASan relies on this annotation to unpoison the stack by inserting calls to _asan_handle_no_return before noreturn functions. This is important for functions that do not return but access the the stack memory, e.g., unwinder functions *like* longjmp (longjmp itself is actually "double-proofed" via its interceptor). The result is that when ASan and UBSan are combined, the noreturn attributes are missing and ASan cannot unpoison the stack, so it has false positives when stack unwinding is used. Changes: Clang-CodeGen now directly insert calls to `__asan_handle_no_return` when a call to a noreturn function is encountered and both UBsan-unreachable and ASan are enabled. This allows UBSan to continue removing the noreturn attribute from functions without any changes to the ASan pass. Previously generated code: ``` call void @longjmp call void @__asan_handle_no_return call void @__ubsan_handle_builtin_unreachable ``` Generated code (for now): ``` call void @__asan_handle_no_return call void @longjmp call void @__asan_handle_no_return call void @__ubsan_handle_builtin_unreachable ``` rdar://problem/40723397 Reviewers: delcypher, eugenis, vsk Differential Revision: https://reviews.llvm.org/D57278 llvm-svn: 352690
Diffstat (limited to 'clang/lib/CodeGen')
-rw-r--r--clang/lib/CodeGen/CGCall.cpp13
-rw-r--r--clang/lib/CodeGen/CodeGenFunction.h4
2 files changed, 15 insertions, 2 deletions
diff --git a/clang/lib/CodeGen/CGCall.cpp b/clang/lib/CodeGen/CGCall.cpp
index 893a6f2f902..655c75c01f6 100644
--- a/clang/lib/CodeGen/CGCall.cpp
+++ b/clang/lib/CodeGen/CGCall.cpp
@@ -4398,10 +4398,23 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
// Strip away the noreturn attribute to better diagnose unreachable UB.
if (SanOpts.has(SanitizerKind::Unreachable)) {
+ // Also remove from function since CI->hasFnAttr(..) also checks attributes
+ // of the called function.
if (auto *F = CI->getCalledFunction())
F->removeFnAttr(llvm::Attribute::NoReturn);
CI->removeAttribute(llvm::AttributeList::FunctionIndex,
llvm::Attribute::NoReturn);
+
+ // Avoid incompatibility with ASan which relies on the `noreturn`
+ // attribute to insert handler calls.
+ if (SanOpts.has(SanitizerKind::Address)) {
+ SanitizerScope SanScope(this);
+ Builder.SetInsertPoint(CI);
+ auto *FnType = llvm::FunctionType::get(CGM.VoidTy, /*isVarArg=*/false);
+ auto *Fn = CGM.CreateRuntimeFunction(FnType, "__asan_handle_no_return");
+ EmitNounwindRuntimeCall(Fn);
+ Builder.SetInsertPoint(CI->getParent());
+ }
}
EmitUnreachable(Loc);
diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h
index a989a0e46ca..575a500c29d 100644
--- a/clang/lib/CodeGen/CodeGenFunction.h
+++ b/clang/lib/CodeGen/CodeGenFunction.h
@@ -4084,8 +4084,8 @@ public:
/// passing to a runtime sanitizer handler.
llvm::Constant *EmitCheckSourceLocation(SourceLocation Loc);
- /// Create a basic block that will call a handler function in a
- /// sanitizer runtime with the provided arguments, and create a conditional
+ /// Create a basic block that will either trap or call a handler function in
+ /// the UBSan runtime with the provided arguments, and create a conditional
/// branch to it.
void EmitCheck(ArrayRef<std::pair<llvm::Value *, SanitizerMask>> Checked,
SanitizerHandler Check, ArrayRef<llvm::Constant *> StaticArgs,
OpenPOWER on IntegriCloud