filcab created this revision. filcab added reviewers: kcc, samsonov, rsmith. filcab added a subscriber: cfe-commits.
This adds a way for us to version any UBSan handler by itself. The patch overrides D21289 for a better implementation (we're able to rev up a single handler). After this, then we can land a slight modification of D19667+D19668. We probably don't want to keep all the versions in compiler-rt (maybe we want to deprecate on one release and remove the old handler on the next one?), but with this patch we will loudly fail to compile when mixing incompatible handler calls, instead of silently compiling and then providing bad error messages. http://reviews.llvm.org/D21695 Files: lib/CodeGen/CGBuiltin.cpp lib/CodeGen/CGCall.cpp lib/CodeGen/CGClass.cpp lib/CodeGen/CGExpr.cpp lib/CodeGen/CGExprScalar.cpp lib/CodeGen/CodeGenFunction.cpp lib/CodeGen/CodeGenFunction.h
Index: lib/CodeGen/CodeGenFunction.h =================================================================== --- lib/CodeGen/CodeGenFunction.h +++ lib/CodeGen/CodeGenFunction.h @@ -100,6 +100,32 @@ TEK_Aggregate }; +#define LIST_SANITIZER_CHECKS \ + SANITIZER_CHECK(AddOverflow, add_overflow, 0) \ + SANITIZER_CHECK(BuiltinUnreachable, builtin_unreachable, 0) \ + SANITIZER_CHECK(CFICheckFail, cfi_check_fail, 0) \ + SANITIZER_CHECK(DivremOverflow, divrem_overflow, 0) \ + SANITIZER_CHECK(DynamicTypeCacheMiss, dynamic_type_cache_miss, 0) \ + SANITIZER_CHECK(FloatCastOverflow, float_cast_overflow, 0) \ + SANITIZER_CHECK(FunctionTypeMismatch, function_type_mismatch, 0) \ + SANITIZER_CHECK(LoadInvalidValue, load_invalid_value, 0) \ + SANITIZER_CHECK(MissingReturn, missing_return, 0) \ + SANITIZER_CHECK(MulOverflow, mul_overflow, 0) \ + SANITIZER_CHECK(NegateOverflow, negate_overflow, 0) \ + SANITIZER_CHECK(NonnullArg, nonnull_arg, 0) \ + SANITIZER_CHECK(NonnullReturn, nonnull_return, 0) \ + SANITIZER_CHECK(OutOfBounds, out_of_bounds, 0) \ + SANITIZER_CHECK(ShiftOutOfBounds, shift_out_of_bounds, 0) \ + SANITIZER_CHECK(SubOverflow, sub_overflow, 0) \ + SANITIZER_CHECK(TypeMismatch, type_mismatch, 0) \ + SANITIZER_CHECK(VLABoundNotPositive, vla_bound_not_positive, 0) + +enum SanitizerHandler { +#define SANITIZER_CHECK(Enum, Name, Version) Enum, + LIST_SANITIZER_CHECKS +#undef SANITIZER_CHECK +}; + /// CodeGenFunction - This class organizes the per-function state that is used /// while generating LLVM code. class CodeGenFunction : public CodeGenTypeCache { @@ -3083,7 +3109,7 @@ /// sanitizer runtime with the provided arguments, and create a conditional /// branch to it. void EmitCheck(ArrayRef<std::pair<llvm::Value *, SanitizerMask>> Checked, - StringRef CheckName, ArrayRef<llvm::Constant *> StaticArgs, + SanitizerHandler Check, ArrayRef<llvm::Constant *> StaticArgs, ArrayRef<llvm::Value *> DynamicArgs); /// \brief Emit a slow path cross-DSO CFI check which calls __cfi_slowpath Index: lib/CodeGen/CodeGenFunction.cpp =================================================================== --- lib/CodeGen/CodeGenFunction.cpp +++ lib/CodeGen/CodeGenFunction.cpp @@ -1036,8 +1036,8 @@ SanitizerScope SanScope(this); llvm::Value *IsFalse = Builder.getFalse(); EmitCheck(std::make_pair(IsFalse, SanitizerKind::Return), - "missing_return", EmitCheckSourceLocation(FD->getLocation()), - None); + SanitizerHandler::MissingReturn, + EmitCheckSourceLocation(FD->getLocation()), None); } else if (CGM.getCodeGenOpts().OptimizationLevel == 0) { EmitTrapCall(llvm::Intrinsic::trap); } @@ -1720,7 +1720,7 @@ }; EmitCheck(std::make_pair(Builder.CreateICmpSGT(Size, Zero), SanitizerKind::VLABound), - "vla_bound_not_positive", StaticArgs, Size); + SanitizerHandler::VLABoundNotPositive, StaticArgs, Size); } // Always zexting here would be wrong if it weren't Index: lib/CodeGen/CGExprScalar.cpp =================================================================== --- lib/CodeGen/CGExprScalar.cpp +++ lib/CodeGen/CGExprScalar.cpp @@ -724,7 +724,7 @@ CGF.EmitCheckTypeDescriptor(OrigSrcType), CGF.EmitCheckTypeDescriptor(DstType)}; CGF.EmitCheck(std::make_pair(Check, SanitizerKind::FloatCastOverflow), - "float_cast_overflow", StaticArgs, OrigSrc); + SanitizerHandler::FloatCastOverflow, StaticArgs, OrigSrc); } /// Emit a conversion from the specified type to the specified destination type, @@ -927,7 +927,7 @@ void ScalarExprEmitter::EmitBinOpCheck( ArrayRef<std::pair<Value *, SanitizerMask>> Checks, const BinOpInfo &Info) { assert(CGF.IsSanitizerScope); - StringRef CheckName; + SanitizerHandler Check; SmallVector<llvm::Constant *, 4> StaticData; SmallVector<llvm::Value *, 2> DynamicData; @@ -938,37 +938,37 @@ StaticData.push_back(CGF.EmitCheckSourceLocation(Info.E->getExprLoc())); const UnaryOperator *UO = dyn_cast<UnaryOperator>(Info.E); if (UO && UO->getOpcode() == UO_Minus) { - CheckName = "negate_overflow"; + Check = SanitizerHandler::NegateOverflow; StaticData.push_back(CGF.EmitCheckTypeDescriptor(UO->getType())); DynamicData.push_back(Info.RHS); } else { if (BinaryOperator::isShiftOp(Opcode)) { // Shift LHS negative or too large, or RHS out of bounds. - CheckName = "shift_out_of_bounds"; + Check = SanitizerHandler::ShiftOutOfBounds; const BinaryOperator *BO = cast<BinaryOperator>(Info.E); StaticData.push_back( CGF.EmitCheckTypeDescriptor(BO->getLHS()->getType())); StaticData.push_back( CGF.EmitCheckTypeDescriptor(BO->getRHS()->getType())); } else if (Opcode == BO_Div || Opcode == BO_Rem) { // Divide or modulo by zero, or signed overflow (eg INT_MAX / -1). - CheckName = "divrem_overflow"; + Check = SanitizerHandler::DivremOverflow; StaticData.push_back(CGF.EmitCheckTypeDescriptor(Info.Ty)); } else { // Arithmetic overflow (+, -, *). switch (Opcode) { - case BO_Add: CheckName = "add_overflow"; break; - case BO_Sub: CheckName = "sub_overflow"; break; - case BO_Mul: CheckName = "mul_overflow"; break; + case BO_Add: Check = SanitizerHandler::AddOverflow; break; + case BO_Sub: Check = SanitizerHandler::SubOverflow; break; + case BO_Mul: Check = SanitizerHandler::MulOverflow; break; default: llvm_unreachable("unexpected opcode for bin op check"); } StaticData.push_back(CGF.EmitCheckTypeDescriptor(Info.Ty)); } DynamicData.push_back(Info.LHS); DynamicData.push_back(Info.RHS); } - CGF.EmitCheck(Checks, CheckName, StaticData, DynamicData); + CGF.EmitCheck(Checks, Check, StaticData, DynamicData); } //===----------------------------------------------------------------------===// Index: lib/CodeGen/CGExpr.cpp =================================================================== --- lib/CodeGen/CGExpr.cpp +++ lib/CodeGen/CGExpr.cpp @@ -589,7 +589,7 @@ llvm::ConstantInt::get(SizeTy, AlignVal), llvm::ConstantInt::get(Int8Ty, TCK) }; - EmitCheck(Checks, "type_mismatch", StaticData, Ptr); + EmitCheck(Checks, SanitizerHandler::TypeMismatch, StaticData, Ptr); } // If possible, check that the vptr indicates that there is a subobject of @@ -657,7 +657,8 @@ }; llvm::Value *DynamicData[] = { Ptr, Hash }; EmitCheck(std::make_pair(EqualHash, SanitizerKind::Vptr), - "dynamic_type_cache_miss", StaticData, DynamicData); + SanitizerHandler::DynamicTypeCacheMiss, StaticData, + DynamicData); } } @@ -745,8 +746,8 @@ }; llvm::Value *Check = Accessed ? Builder.CreateICmpULT(IndexVal, BoundVal) : Builder.CreateICmpULE(IndexVal, BoundVal); - EmitCheck(std::make_pair(Check, SanitizerKind::ArrayBounds), "out_of_bounds", - StaticData, Index); + EmitCheck(std::make_pair(Check, SanitizerKind::ArrayBounds), + SanitizerHandler::OutOfBounds, StaticData, Index); } @@ -1318,8 +1319,8 @@ EmitCheckTypeDescriptor(Ty) }; SanitizerMask Kind = NeedsEnumCheck ? SanitizerKind::Enum : SanitizerKind::Bool; - EmitCheck(std::make_pair(Check, Kind), "load_invalid_value", StaticArgs, - EmitCheckValue(Load)); + EmitCheck(std::make_pair(Check, Kind), SanitizerHandler::LoadInvalidValue, + StaticArgs, EmitCheckValue(Load)); } } else if (CGM.getCodeGenOpts().OptimizationLevel > 0) if (llvm::MDNode *RangeInfo = getRangeForLoadFromType(Ty)) @@ -2443,17 +2444,35 @@ } } +namespace { +struct SanitizerHandlerInfo { + char const *const Name; + unsigned Version; +}; +}; + +const SanitizerHandlerInfo SanitizerHandlers[] = { +#define SANITIZER_CHECK(Enum, Name, Version) {#Name, Version}, + LIST_SANITIZER_CHECKS +#undef SANITIZER_CHECK +}; + static void emitCheckHandlerCall(CodeGenFunction &CGF, llvm::FunctionType *FnType, ArrayRef<llvm::Value *> FnArgs, - StringRef CheckName, + SanitizerHandler CheckHandler, CheckRecoverableKind RecoverKind, bool IsFatal, llvm::BasicBlock *ContBB) { assert(IsFatal || RecoverKind != CheckRecoverableKind::Unrecoverable); bool NeedsAbortSuffix = IsFatal && RecoverKind != CheckRecoverableKind::Unrecoverable; - std::string FnName = ("__ubsan_handle_" + CheckName + - (NeedsAbortSuffix ? "_abort" : "")).str(); + const SanitizerHandlerInfo &CheckInfo = SanitizerHandlers[CheckHandler]; + const StringRef CheckName = CheckInfo.Name; + std::string FnName = + ("__ubsan_handle_" + CheckName + + (CheckInfo.Version ? "_v" + std::to_string(CheckInfo.Version) : "") + + (NeedsAbortSuffix ? "_abort" : "")) + .str(); bool MayReturn = !IsFatal || RecoverKind == CheckRecoverableKind::AlwaysRecoverable; @@ -2479,10 +2498,13 @@ void CodeGenFunction::EmitCheck( ArrayRef<std::pair<llvm::Value *, SanitizerMask>> Checked, - StringRef CheckName, ArrayRef<llvm::Constant *> StaticArgs, + SanitizerHandler CheckHandler, ArrayRef<llvm::Constant *> StaticArgs, ArrayRef<llvm::Value *> DynamicArgs) { assert(IsSanitizerScope); assert(Checked.size() > 0); + assert(CheckHandler >= 0 && + CheckHandler < sizeof(SanitizerHandlers) / sizeof(*SanitizerHandlers)); + const StringRef CheckName = SanitizerHandlers[CheckHandler].Name; llvm::Value *FatalCond = nullptr; llvm::Value *RecoverableCond = nullptr; @@ -2562,7 +2584,7 @@ if (!FatalCond || !RecoverableCond) { // Simple case: we need to generate a single handler call, either // fatal, or non-fatal. - emitCheckHandlerCall(*this, FnType, Args, CheckName, RecoverKind, + emitCheckHandlerCall(*this, FnType, Args, CheckHandler, RecoverKind, (FatalCond != nullptr), Cont); } else { // Emit two handler calls: first one for set of unrecoverable checks, @@ -2572,10 +2594,10 @@ llvm::BasicBlock *FatalHandlerBB = createBasicBlock("fatal." + CheckName); Builder.CreateCondBr(FatalCond, NonFatalHandlerBB, FatalHandlerBB); EmitBlock(FatalHandlerBB); - emitCheckHandlerCall(*this, FnType, Args, CheckName, RecoverKind, true, + emitCheckHandlerCall(*this, FnType, Args, CheckHandler, RecoverKind, true, NonFatalHandlerBB); EmitBlock(NonFatalHandlerBB); - emitCheckHandlerCall(*this, FnType, Args, CheckName, RecoverKind, false, + emitCheckHandlerCall(*this, FnType, Args, CheckHandler, RecoverKind, false, Cont); } @@ -2700,7 +2722,7 @@ llvm::Value *Cond = Builder.CreateICmpNE(CheckKind, llvm::ConstantInt::get(Int8Ty, Kind)); if (CGM.getLangOpts().Sanitize.has(Mask)) - EmitCheck(std::make_pair(Cond, Mask), "cfi_check_fail", {}, + EmitCheck(std::make_pair(Cond, Mask), SanitizerHandler::CFICheckFail, {}, {Data, Addr, ValidVtable}); else EmitTrapCheck(Cond); @@ -4035,7 +4057,7 @@ EmitCheckTypeDescriptor(CalleeType) }; EmitCheck(std::make_pair(CalleeRTTIMatch, SanitizerKind::Function), - "function_type_mismatch", StaticData, Callee); + SanitizerHandler::FunctionTypeMismatch, StaticData, Callee); Builder.CreateBr(Cont); EmitBlock(Cont); @@ -4068,7 +4090,7 @@ CastedCallee, StaticData); } else { EmitCheck(std::make_pair(BitSetTest, SanitizerKind::CFIICall), - "cfi_check_fail", StaticData, + SanitizerHandler::CFICheckFail, StaticData, {CastedCallee, llvm::UndefValue::get(IntPtrTy)}); } } Index: lib/CodeGen/CGClass.cpp =================================================================== --- lib/CodeGen/CGClass.cpp +++ lib/CodeGen/CGClass.cpp @@ -2643,8 +2643,8 @@ llvm::Value *ValidVtable = Builder.CreateCall(CGM.getIntrinsic(llvm::Intrinsic::bitset_test), {CastedVTable, AllVtables}); - EmitCheck(std::make_pair(BitSetTest, M), "cfi_check_fail", StaticData, - {CastedVTable, ValidVtable}); + EmitCheck(std::make_pair(BitSetTest, M), SanitizerHandler::CFICheckFail, + StaticData, {CastedVTable, ValidVtable}); } // FIXME: Ideally Expr::IgnoreParenNoopCasts should do this, but it doesn't do Index: lib/CodeGen/CGCall.cpp =================================================================== --- lib/CodeGen/CGCall.cpp +++ lib/CodeGen/CGCall.cpp @@ -2818,7 +2818,7 @@ EmitCheckSourceLocation(RetNNAttr->getLocation()), }; EmitCheck(std::make_pair(Cond, SanitizerKind::ReturnsNonnullAttribute), - "nonnull_return", StaticData, None); + SanitizerHandler::NonnullReturn, StaticData, None); } } Ret = Builder.CreateRet(RV); @@ -3144,7 +3144,7 @@ llvm::ConstantInt::get(Int32Ty, ArgNo + 1), }; EmitCheck(std::make_pair(Cond, SanitizerKind::NonnullAttribute), - "nonnull_arg", StaticData, None); + SanitizerHandler::NonnullArg, StaticData, None); } void CodeGenFunction::EmitCallArgs( Index: lib/CodeGen/CGBuiltin.cpp =================================================================== --- lib/CodeGen/CGBuiltin.cpp +++ lib/CodeGen/CGBuiltin.cpp @@ -724,8 +724,8 @@ SanitizerScope SanScope(this); EmitCheck(std::make_pair(static_cast<llvm::Value *>(Builder.getFalse()), SanitizerKind::Unreachable), - "builtin_unreachable", EmitCheckSourceLocation(E->getExprLoc()), - None); + SanitizerHandler::BuiltinUnreachable, + EmitCheckSourceLocation(E->getExprLoc()), None); } else Builder.CreateUnreachable();
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits