yln updated this revision to Diff 184168. yln added a comment. Directly insert calls to `__asan_handle_no_return`
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. CHANGES SINCE LAST ACTION https://reviews.llvm.org/D57278/new/ https://reviews.llvm.org/D57278 Files: clang/lib/CodeGen/CGCall.cpp clang/lib/CodeGen/CodeGenFunction.h clang/test/CodeGen/ubsan-asan-noreturn.c clang/test/CodeGenCXX/ubsan-unreachable.cpp
Index: clang/test/CodeGenCXX/ubsan-unreachable.cpp =================================================================== --- clang/test/CodeGenCXX/ubsan-unreachable.cpp +++ clang/test/CodeGenCXX/ubsan-unreachable.cpp @@ -1,39 +1,37 @@ // RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -o - %s -fsanitize=unreachable | FileCheck %s -extern void __attribute__((noreturn)) abort(); +void abort() __attribute__((noreturn)); -// CHECK-LABEL: define void @_Z14calls_noreturnv +// CHECK-LABEL: define void @_Z14calls_noreturnv() void calls_noreturn() { + // Check absence ([^#]*) of call site attributes (including noreturn) + // CHECK: call void @_Z5abortv(){{[^#]*}} abort(); - // Check that there are no attributes on the call site. - // CHECK-NOT: call void @_Z5abortv{{.*}}# - // CHECK: __ubsan_handle_builtin_unreachable // CHECK: unreachable } struct A { - // CHECK: declare void @_Z5abortv{{.*}} [[ABORT_ATTR:#[0-9]+]] + // CHECK: declare void @_Z5abortv() [[EXTERN_FN_ATTR:#[0-9]+]] // CHECK-LABEL: define linkonce_odr void @_ZN1A5call1Ev void call1() { - // CHECK-NOT: call void @_ZN1A16does_not_return2Ev{{.*}}# + // CHECK: call void @_ZN1A16does_not_return2Ev({{.*}}){{[^#]*}} does_not_return2(); // CHECK: __ubsan_handle_builtin_unreachable // CHECK: unreachable } - // Test static members. - static void __attribute__((noreturn)) does_not_return1() { - // CHECK-NOT: call void @_Z5abortv{{.*}}# + // Test static members. Checks are below after `struct A` scope ends. + static void does_not_return1() __attribute__((noreturn)) { abort(); } // CHECK-LABEL: define linkonce_odr void @_ZN1A5call2Ev void call2() { - // CHECK-NOT: call void @_ZN1A16does_not_return1Ev{{.*}}# + // CHECK: call void @_ZN1A16does_not_return1Ev(){{[^#]*}} does_not_return1(); // CHECK: __ubsan_handle_builtin_unreachable @@ -41,23 +39,23 @@ } // Test calls through pointers to non-static member functions. - typedef void __attribute__((noreturn)) (A::*MemFn)(); + typedef void (A::*MemFn)() __attribute__((noreturn)); // CHECK-LABEL: define linkonce_odr void @_ZN1A5call3Ev void call3() { MemFn MF = &A::does_not_return2; + // CHECK: call void %{{[0-9]+\(.*}}){{[^#]*}} (this->*MF)(); - // CHECK-NOT: call void %{{.*}}# // CHECK: __ubsan_handle_builtin_unreachable // CHECK: unreachable } // Test regular members. // CHECK-LABEL: define linkonce_odr void @_ZN1A16does_not_return2Ev({{.*}}) - // CHECK-SAME: [[DOES_NOT_RETURN_ATTR:#[0-9]+]] - void __attribute__((noreturn)) does_not_return2() { - // CHECK-NOT: call void @_Z5abortv(){{.*}}# + // CHECK-SAME: [[USER_FN_ATTR:#[0-9]+]] + void does_not_return2() __attribute__((noreturn)) { + // CHECK: call void @_Z5abortv(){{[^#]*}} abort(); // CHECK: call void @__ubsan_handle_builtin_unreachable @@ -68,7 +66,9 @@ } }; -// CHECK: define linkonce_odr void @_ZN1A16does_not_return1Ev() [[DOES_NOT_RETURN_ATTR]] +// CHECK-LABEL: define linkonce_odr void @_ZN1A16does_not_return1Ev() +// CHECK-SAME: [[USER_FN_ATTR]] +// CHECK: call void @_Z5abortv(){{[^#]*}} void force_irgen() { A a; @@ -77,5 +77,7 @@ a.call3(); } -// CHECK-NOT: [[ABORT_ATTR]] = {{[^}]+}}noreturn -// CHECK-NOT: [[DOES_NOT_RETURN_ATTR]] = {{[^}]+}}noreturn +// `noreturn` should be removed from functions and call sites +// CHECK-LABEL: attributes +// CHECK-NOT: [[USER_FN_ATTR]] = { {{.*noreturn.*}} } +// CHECK-NOT: [[EXTERN_FN_ATTR]] = { {{.*noreturn.*}} } Index: clang/test/CodeGen/ubsan-asan-noreturn.c =================================================================== --- /dev/null +++ clang/test/CodeGen/ubsan-asan-noreturn.c @@ -0,0 +1,21 @@ +// Ensure compatiblity of UBSan unreachable with ASan in the presence of +// noreturn functions. +// RUN: %clang_cc1 -fsanitize=unreachable,address -triple x86_64-linux -emit-llvm -o - %s | FileCheck %s + +void my_longjmp(void) __attribute__((noreturn)); + +// CHECK-LABEL: define void @calls_noreturn() +void calls_noreturn() { + my_longjmp(); + // CHECK: @__asan_handle_no_return{{.*}} !nosanitize + // CHECK-NEXT: @my_longjmp(){{[^#]*}} + // CHECK: @__asan_handle_no_return() + // CHECK-NEXT: @__ubsan_handle_builtin_unreachable{{.*}} !nosanitize + // CHECK-NEXT: unreachable +} + +// CHECK: declare void @my_longjmp() [[FN_ATTR:#[0-9]+]] +// CHECK: declare void @__asan_handle_no_return() + +// CHECK-LABEL: attributes +// CHECK-NOT: [[FN_ATTR]] = { {{.*noreturn.*}} } Index: clang/lib/CodeGen/CodeGenFunction.h =================================================================== --- clang/lib/CodeGen/CodeGenFunction.h +++ clang/lib/CodeGen/CodeGenFunction.h @@ -4085,8 +4085,8 @@ /// 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, Index: clang/lib/CodeGen/CGCall.cpp =================================================================== --- clang/lib/CodeGen/CGCall.cpp +++ clang/lib/CodeGen/CGCall.cpp @@ -4403,10 +4403,23 @@ // Strip away the noreturn attribute to better diagnose unreachable UB. if (SanOpts.has(SanitizerKind::Unreachable)) { + // Also remove from function since CS.hasFnAttr(..) also checks attributes + // of the called function. if (auto *F = CS.getCalledFunction()) F->removeFnAttr(llvm::Attribute::NoReturn); CS.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(CS.getInstruction()); + auto *FnType = llvm::FunctionType::get(CGM.VoidTy, /*isVarArg=*/false); + auto *Fn = CGM.CreateRuntimeFunction(FnType, "__asan_handle_no_return"); + EmitNounwindRuntimeCall(Fn); + Builder.SetInsertPoint(CS->getParent()); + } } EmitUnreachable(Loc);
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits