diff options
author | Vedant Kumar <vsk@apple.com> | 2017-12-21 00:10:25 +0000 |
---|---|---|
committer | Vedant Kumar <vsk@apple.com> | 2017-12-21 00:10:25 +0000 |
commit | 09b5bfdd85fa23a331ee565bda289b3c27c00fdf (patch) | |
tree | a5adff5e6bd5871fe32873bd2e3da642ba0f6247 /clang/lib | |
parent | fae4f7c6818343acc9ad54cacaadaf9fc6fcf52d (diff) | |
download | bcm5719-llvm-09b5bfdd85fa23a331ee565bda289b3c27c00fdf.tar.gz bcm5719-llvm-09b5bfdd85fa23a331ee565bda289b3c27c00fdf.zip |
[ubsan] Diagnose noreturn functions which return
Diagnose 'unreachable' UB when a noreturn function returns.
1. Insert a check at the end of functions marked noreturn.
2. A decl may be marked noreturn in the caller TU, but not marked in
the TU where it's defined. To diagnose this scenario, strip away the
noreturn attribute on the callee and insert check after calls to it.
Testing: check-clang, check-ubsan, check-ubsan-minimal, D40700
rdar://33660464
Differential Revision: https://reviews.llvm.org/D40698
llvm-svn: 321231
Diffstat (limited to 'clang/lib')
-rw-r--r-- | clang/lib/CodeGen/CGBuiltin.cpp | 9 | ||||
-rw-r--r-- | clang/lib/CodeGen/CGCall.cpp | 19 | ||||
-rw-r--r-- | clang/lib/CodeGen/CGExpr.cpp | 13 | ||||
-rw-r--r-- | clang/lib/CodeGen/CGExprCXX.cpp | 5 | ||||
-rw-r--r-- | clang/lib/CodeGen/CodeGenFunction.h | 16 |
5 files changed, 45 insertions, 17 deletions
diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index 01cc0187fb5..d67f2fede38 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -1432,14 +1432,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, case Builtin::BI__debugbreak: return RValue::get(EmitTrapCall(Intrinsic::debugtrap)); case Builtin::BI__builtin_unreachable: { - if (SanOpts.has(SanitizerKind::Unreachable)) { - SanitizerScope SanScope(this); - EmitCheck(std::make_pair(static_cast<llvm::Value *>(Builder.getFalse()), - SanitizerKind::Unreachable), - SanitizerHandler::BuiltinUnreachable, - EmitCheckSourceLocation(E->getExprLoc()), None); - } else - Builder.CreateUnreachable(); + EmitUnreachable(E->getExprLoc()); // We do need to preserve an insertion point. EmitBlock(createBasicBlock("unreachable.cont")); diff --git a/clang/lib/CodeGen/CGCall.cpp b/clang/lib/CodeGen/CGCall.cpp index eea074e0307..38d7344572d 100644 --- a/clang/lib/CodeGen/CGCall.cpp +++ b/clang/lib/CodeGen/CGCall.cpp @@ -2758,6 +2758,12 @@ static llvm::StoreInst *findDominatingStoreToReturnValue(CodeGenFunction &CGF) { void CodeGenFunction::EmitFunctionEpilog(const CGFunctionInfo &FI, bool EmitRetDbgLoc, SourceLocation EndLoc) { + if (FI.isNoReturn()) { + // Noreturn functions don't return. + EmitUnreachable(EndLoc); + return; + } + if (CurCodeDecl && CurCodeDecl->hasAttr<NakedAttr>()) { // Naked functions don't have epilogues. Builder.CreateUnreachable(); @@ -3718,7 +3724,8 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo, const CGCallee &Callee, ReturnValueSlot ReturnValue, const CallArgList &CallArgs, - llvm::Instruction **callOrInvoke) { + llvm::Instruction **callOrInvoke, + SourceLocation Loc) { // FIXME: We no longer need the types from CallArgs; lift up and simplify. assert(Callee.isOrdinary()); @@ -4241,7 +4248,15 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo, EmitLifetimeEnd(llvm::ConstantInt::get(Int64Ty, UnusedReturnSize), SRetPtr.getPointer()); - Builder.CreateUnreachable(); + // Strip away the noreturn attribute to better diagnose unreachable UB. + if (SanOpts.has(SanitizerKind::Unreachable)) { + if (auto *F = CS.getCalledFunction()) + F->removeFnAttr(llvm::Attribute::NoReturn); + CS.removeAttribute(llvm::AttributeList::FunctionIndex, + llvm::Attribute::NoReturn); + } + + EmitUnreachable(Loc); Builder.ClearInsertionPoint(); // FIXME: For now, emit a dummy basic block because expr emitters in diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp index 98740e8f9aa..b61b273977d 100644 --- a/clang/lib/CodeGen/CGExpr.cpp +++ b/clang/lib/CodeGen/CGExpr.cpp @@ -3076,6 +3076,17 @@ void CodeGenFunction::EmitCfiCheckFail() { CGM.addUsedGlobal(F); } +void CodeGenFunction::EmitUnreachable(SourceLocation Loc) { + if (SanOpts.has(SanitizerKind::Unreachable)) { + SanitizerScope SanScope(this); + EmitCheck(std::make_pair(static_cast<llvm::Value *>(Builder.getFalse()), + SanitizerKind::Unreachable), + SanitizerHandler::BuiltinUnreachable, + EmitCheckSourceLocation(Loc), None); + } + Builder.CreateUnreachable(); +} + void CodeGenFunction::EmitTrapCheck(llvm::Value *Checked) { llvm::BasicBlock *Cont = createBasicBlock("cont"); @@ -4616,7 +4627,7 @@ RValue CodeGenFunction::EmitCall(QualType CalleeType, const CGCallee &OrigCallee Callee.setFunctionPointer(CalleePtr); } - return EmitCall(FnInfo, Callee, ReturnValue, Args); + return EmitCall(FnInfo, Callee, ReturnValue, Args, nullptr, E->getExprLoc()); } LValue CodeGenFunction:: diff --git a/clang/lib/CodeGen/CGExprCXX.cpp b/clang/lib/CodeGen/CGExprCXX.cpp index 9e301bd0574..0749b0ac46a 100644 --- a/clang/lib/CodeGen/CGExprCXX.cpp +++ b/clang/lib/CodeGen/CGExprCXX.cpp @@ -89,7 +89,8 @@ RValue CodeGenFunction::EmitCXXMemberOrOperatorCall( *this, MD, This, ImplicitParam, ImplicitParamTy, CE, Args, RtlArgs); auto &FnInfo = CGM.getTypes().arrangeCXXMethodCall( Args, FPT, CallInfo.ReqArgs, CallInfo.PrefixSize); - return EmitCall(FnInfo, Callee, ReturnValue, Args); + return EmitCall(FnInfo, Callee, ReturnValue, Args, nullptr, + CE ? CE->getExprLoc() : SourceLocation()); } RValue CodeGenFunction::EmitCXXDestructorCall( @@ -446,7 +447,7 @@ CodeGenFunction::EmitCXXMemberPointerCallExpr(const CXXMemberCallExpr *E, EmitCallArgs(Args, FPT, E->arguments()); return EmitCall(CGM.getTypes().arrangeCXXMethodCall(Args, FPT, required, /*PrefixSize=*/0), - Callee, ReturnValue, Args); + Callee, ReturnValue, Args, nullptr, E->getExprLoc()); } RValue diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h index ab5bbc03db9..c6ee97142aa 100644 --- a/clang/lib/CodeGen/CodeGenFunction.h +++ b/clang/lib/CodeGen/CodeGenFunction.h @@ -3288,11 +3288,15 @@ public: /// LLVM arguments and the types they were derived from. RValue EmitCall(const CGFunctionInfo &CallInfo, const CGCallee &Callee, ReturnValueSlot ReturnValue, const CallArgList &Args, - llvm::Instruction **callOrInvoke = nullptr); - + llvm::Instruction **callOrInvoke, SourceLocation Loc); + RValue EmitCall(const CGFunctionInfo &CallInfo, const CGCallee &Callee, + ReturnValueSlot ReturnValue, const CallArgList &Args, + llvm::Instruction **callOrInvoke = nullptr) { + return EmitCall(CallInfo, Callee, ReturnValue, Args, callOrInvoke, + SourceLocation()); + } RValue EmitCall(QualType FnType, const CGCallee &Callee, const CallExpr *E, - ReturnValueSlot ReturnValue, - llvm::Value *Chain = nullptr); + ReturnValueSlot ReturnValue, llvm::Value *Chain = nullptr); RValue EmitCallExpr(const CallExpr *E, ReturnValueSlot ReturnValue = ReturnValueSlot()); RValue EmitSimpleCallExpr(const CallExpr *E, ReturnValueSlot ReturnValue); @@ -3747,6 +3751,10 @@ public: llvm::ConstantInt *TypeId, llvm::Value *Ptr, ArrayRef<llvm::Constant *> StaticArgs); + /// Emit a reached-unreachable diagnostic if \p Loc is valid and runtime + /// checking is enabled. Otherwise, just emit an unreachable instruction. + void EmitUnreachable(SourceLocation Loc); + /// \brief Create a basic block that will call the trap intrinsic, and emit a /// conditional branch to it, for the -ftrapv checks. void EmitTrapCheck(llvm::Value *Checked); |