Hi rsmith,
This change adds "!ubsan" metadata to all the instructions
generated by Clang CodeGen to implement variety of UBSan checks. This
metadata can later be used by ASan instrumentation pass in LLVM backend
to avoid instrumenting UBSan-generated code. This should fix PR20085.
http://reviews.llvm.org/D4544
Files:
lib/Transforms/Instrumentation/AddressSanitizer.cpp
test/Instrumentation/AddressSanitizer/ubsan.ll
tools/clang/lib/CodeGen/CGBuiltin.cpp
tools/clang/lib/CodeGen/CGExpr.cpp
tools/clang/lib/CodeGen/CGExprScalar.cpp
tools/clang/lib/CodeGen/CodeGenFunction.cpp
tools/clang/lib/CodeGen/CodeGenFunction.h
tools/clang/test/CodeGen/catch-undef-behavior.c
Index: lib/Transforms/Instrumentation/AddressSanitizer.cpp
===================================================================
--- lib/Transforms/Instrumentation/AddressSanitizer.cpp
+++ lib/Transforms/Instrumentation/AddressSanitizer.cpp
@@ -655,6 +655,9 @@
// and set IsWrite/Alignment. Otherwise return NULL.
static Value *isInterestingMemoryAccess(Instruction *I, bool *IsWrite,
unsigned *Alignment) {
+ // Skip memory accesses inserted by UBSan.
+ if (I->getMetadata("ubsan"))
+ return nullptr;
if (LoadInst *LI = dyn_cast<LoadInst>(I)) {
if (!ClInstrumentReads) return nullptr;
*IsWrite = false;
Index: test/Instrumentation/AddressSanitizer/ubsan.ll
===================================================================
--- /dev/null
+++ test/Instrumentation/AddressSanitizer/ubsan.ll
@@ -0,0 +1,52 @@
+; ASan shouldn't instrument code added by UBSan.
+
+; RUN: opt < %s -asan -asan-module -S | FileCheck %s
+
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"
+target triple = "x86_64-unknown-linux-gnu"
+
+%struct.A = type { i32 (...)** }
+declare void @__ubsan_handle_dynamic_type_cache_miss(i8*, i64, i64) uwtable
+@__ubsan_vptr_type_cache = external global [128 x i64]
[email protected] = private unnamed_addr constant [19 x i8] c"tmp/ubsan/vptr.cpp\00", align 1
+@0 = private unnamed_addr constant { i16, i16, [4 x i8] } { i16 -1, i16 0, [4 x i8] c"'A'\00" }
+@_ZTI1A = external constant i8*
+@1 = private unnamed_addr global { { [19 x i8]*, i32, i32 }, { i16, i16, [4 x i8] }*, i8*, i8 } { { [19 x i8]*, i32, i32 } { [19 x i8]* @.src, i32 2, i32 18 }, { i16, i16, [4 x i8] }* @0, i8* bitcast (i8** @_ZTI1A to i8*), i8 4 }
+
+define void @_Z3BarP1A(%struct.A* %a) uwtable sanitize_address {
+; CHECK-LABEL: define void @_Z3BarP1A
+entry:
+ %0 = bitcast %struct.A* %a to void (%struct.A*)***
+ %vtable = load void (%struct.A*)*** %0, align 8
+; CHECK: __asan_report_load8
+ %1 = load void (%struct.A*)** %vtable, align 8
+; CHECK: __asan_report_load8
+ %2 = ptrtoint void (%struct.A*)** %vtable to i64
+ %3 = xor i64 %2, -303164226014115343, !ubsan !0
+ %4 = mul i64 %3, -7070675565921424023, !ubsan !0
+ %5 = lshr i64 %4, 47, !ubsan !0
+ %6 = xor i64 %4, %2, !ubsan !0
+ %7 = xor i64 %6, %5, !ubsan !0
+ %8 = mul i64 %7, -7070675565921424023, !ubsan !0
+ %9 = lshr i64 %8, 47, !ubsan !0
+ %10 = xor i64 %9, %8, !ubsan !0
+ %11 = mul i64 %10, -7070675565921424023, !ubsan !0
+ %12 = and i64 %11, 127, !ubsan !0
+ %13 = getelementptr inbounds [128 x i64]* @__ubsan_vptr_type_cache, i64 0, i64 %12, !ubsan !0
+; CHECK-NOT: __asan_report_load8
+ %14 = load i64* %13, align 8, !ubsan !0
+ %15 = icmp eq i64 %14, %11, !ubsan !0
+ br i1 %15, label %cont, label %handler.dynamic_type_cache_miss, !ubsan !0
+
+handler.dynamic_type_cache_miss: ; preds = %entry
+ %16 = ptrtoint %struct.A* %a to i64, !ubsan !0
+ tail call void @__ubsan_handle_dynamic_type_cache_miss(i8* bitcast ({ { [19 x i8]*, i32, i32 }, { i16, i16, [4 x i8] }*, i8*, i8 }* @1 to i8*), i64 %16, i64 %11) #2, !ubsan !0
+ br label %cont, !ubsan !0
+
+cont: ; preds = %handler.dynamic_type_cache_miss, %entry
+ tail call void %1(%struct.A* %a)
+; CHECK: ret void
+ ret void
+}
+
+!0 = metadata !{}
Index: tools/clang/lib/CodeGen/CGExpr.cpp
===================================================================
--- tools/clang/lib/CodeGen/CGExpr.cpp
+++ tools/clang/lib/CodeGen/CGExpr.cpp
@@ -458,6 +458,8 @@
if (Address->getType()->getPointerAddressSpace())
return;
+ SanitizerScope SanScope(this);
+
llvm::Value *Cond = nullptr;
llvm::BasicBlock *Done = nullptr;
@@ -654,6 +656,7 @@
bool Accessed) {
assert(SanOpts->ArrayBounds &&
"should not be called unless adding bounds checks");
+ SanitizerScope SanScope(this);
QualType IndexedType;
llvm::Value *Bound = getArrayIndexingBound(*this, Base, IndexedType);
@@ -1129,6 +1132,7 @@
if ((SanOpts->Bool && hasBooleanRepresentation(Ty)) ||
(SanOpts->Enum && Ty->getAs<EnumType>())) {
+ SanitizerScope SanScope(this);
llvm::APInt Min, End;
if (getRangeForType(*this, Ty, Min, End, true)) {
--End;
@@ -2183,6 +2187,7 @@
ArrayRef<llvm::Value *> DynamicArgs,
CheckRecoverableKind RecoverKind) {
assert(SanOpts != &SanitizerOptions::Disabled);
+ assert(IsSanitizerScope);
if (CGM.getCodeGenOpts().SanitizeUndefinedTrapOnError) {
assert (RecoverKind != CRK_AlwaysRecoverable &&
@@ -3231,6 +3236,7 @@
(!TargetDecl || !isa<FunctionDecl>(TargetDecl))) {
if (llvm::Constant *PrefixSig =
CGM.getTargetCodeGenInfo().getUBSanFunctionSignature(CGM)) {
+ SanitizerScope SanScope(this);
llvm::Constant *FTRTTIConst =
CGM.GetAddrOfRTTIDescriptor(QualType(FnType, 0), /*ForEH=*/true);
llvm::Type *PrefixStructTyElems[] = {
Index: tools/clang/lib/CodeGen/CGExprScalar.cpp
===================================================================
--- tools/clang/lib/CodeGen/CGExprScalar.cpp
+++ tools/clang/lib/CodeGen/CGExprScalar.cpp
@@ -554,6 +554,7 @@
Value *Src, QualType SrcType,
QualType DstType,
llvm::Type *DstTy) {
+ CodeGenFunction::SanitizerScope SanScope(&CGF);
using llvm::APFloat;
using llvm::APSInt;
@@ -835,6 +836,7 @@
/// might actually be a unary increment which has been lowered to a binary
/// operation). The check passes if \p Check, which is an \c i1, is \c true.
void ScalarExprEmitter::EmitBinOpCheck(Value *Check, const BinOpInfo &Info) {
+ assert(CGF.IsSanitizerScope);
StringRef CheckName;
SmallVector<llvm::Constant *, 4> StaticData;
SmallVector<llvm::Value *, 2> DynamicData;
@@ -2146,15 +2148,18 @@
}
Value *ScalarExprEmitter::EmitDiv(const BinOpInfo &Ops) {
- if ((CGF.SanOpts->IntegerDivideByZero ||
- CGF.SanOpts->SignedIntegerOverflow) &&
- Ops.Ty->isIntegerType()) {
- llvm::Value *Zero = llvm::Constant::getNullValue(ConvertType(Ops.Ty));
- EmitUndefinedBehaviorIntegerDivAndRemCheck(Ops, Zero, true);
- } else if (CGF.SanOpts->FloatDivideByZero &&
- Ops.Ty->isRealFloatingType()) {
- llvm::Value *Zero = llvm::Constant::getNullValue(ConvertType(Ops.Ty));
- EmitBinOpCheck(Builder.CreateFCmpUNE(Ops.RHS, Zero), Ops);
+ {
+ CodeGenFunction::SanitizerScope SanScope(&CGF);
+ if ((CGF.SanOpts->IntegerDivideByZero ||
+ CGF.SanOpts->SignedIntegerOverflow) &&
+ Ops.Ty->isIntegerType()) {
+ llvm::Value *Zero = llvm::Constant::getNullValue(ConvertType(Ops.Ty));
+ EmitUndefinedBehaviorIntegerDivAndRemCheck(Ops, Zero, true);
+ } else if (CGF.SanOpts->FloatDivideByZero &&
+ Ops.Ty->isRealFloatingType()) {
+ llvm::Value *Zero = llvm::Constant::getNullValue(ConvertType(Ops.Ty));
+ EmitBinOpCheck(Builder.CreateFCmpUNE(Ops.RHS, Zero), Ops);
+ }
}
if (Ops.LHS->getType()->isFPOrFPVectorTy()) {
@@ -2178,6 +2183,7 @@
Value *ScalarExprEmitter::EmitRem(const BinOpInfo &Ops) {
// Rem in C can't be a floating point type: C99 6.5.5p2.
if (CGF.SanOpts->IntegerDivideByZero) {
+ CodeGenFunction::SanitizerScope SanScope(&CGF);
llvm::Value *Zero = llvm::Constant::getNullValue(ConvertType(Ops.Ty));
if (Ops.Ty->isIntegerType())
@@ -2235,9 +2241,10 @@
if (handlerName->empty()) {
// If the signed-integer-overflow sanitizer is enabled, emit a call to its
// runtime. Otherwise, this is a -ftrapv check, so just emit a trap.
- if (!isSigned || CGF.SanOpts->SignedIntegerOverflow)
+ if (!isSigned || CGF.SanOpts->SignedIntegerOverflow) {
+ CodeGenFunction::SanitizerScope SanScope(&CGF);
EmitBinOpCheck(Builder.CreateNot(overflow), Ops);
- else
+ } else
CGF.EmitTrapCheck(Builder.CreateNot(overflow));
return result;
}
@@ -2589,6 +2596,7 @@
if (CGF.SanOpts->Shift && !CGF.getLangOpts().OpenCL &&
isa<llvm::IntegerType>(Ops.LHS->getType())) {
+ CodeGenFunction::SanitizerScope SanScope(&CGF);
llvm::Value *WidthMinusOne = GetWidthMinusOneValue(Ops.LHS, RHS);
llvm::Value *Valid = Builder.CreateICmpULE(RHS, WidthMinusOne);
@@ -2640,8 +2648,10 @@
RHS = Builder.CreateIntCast(RHS, Ops.LHS->getType(), false, "sh_prom");
if (CGF.SanOpts->Shift && !CGF.getLangOpts().OpenCL &&
- isa<llvm::IntegerType>(Ops.LHS->getType()))
+ isa<llvm::IntegerType>(Ops.LHS->getType())) {
+ CodeGenFunction::SanitizerScope SanScope(&CGF);
EmitBinOpCheck(Builder.CreateICmpULE(RHS, GetWidthMinusOneValue(Ops.LHS, RHS)), Ops);
+ }
// OpenCL 6.3j: shift values are effectively % word size of LHS.
if (CGF.getLangOpts().OpenCL)
Index: tools/clang/lib/CodeGen/CodeGenFunction.h
===================================================================
--- tools/clang/lib/CodeGen/CodeGenFunction.h
+++ tools/clang/lib/CodeGen/CodeGenFunction.h
@@ -247,6 +247,17 @@
/// \brief Sanitizer options to use for this function.
const SanitizerOptions *SanOpts;
+ /// \brief True if CodeGen currently emits code implementing sanitizer checks.
+ bool IsSanitizerScope;
+
+ /// \brief RAII object to set/unset CodeGenFunction::IsSanitizerScope.
+ class SanitizerScope {
+ CodeGenFunction *CGF;
+ public:
+ SanitizerScope(CodeGenFunction *CGF);
+ ~SanitizerScope();
+ };
+
/// In ARC, whether we should autorelease the return value.
bool AutoreleaseResult;
Index: tools/clang/lib/CodeGen/CGBuiltin.cpp
===================================================================
--- tools/clang/lib/CodeGen/CGBuiltin.cpp
+++ tools/clang/lib/CodeGen/CGBuiltin.cpp
@@ -447,11 +447,12 @@
return RValue::get(Builder.CreateCall(F));
}
case Builtin::BI__builtin_unreachable: {
- if (SanOpts->Unreachable)
+ if (SanOpts->Unreachable) {
+ SanitizerScope SanScope(this);
EmitCheck(Builder.getFalse(), "builtin_unreachable",
EmitCheckSourceLocation(E->getExprLoc()),
ArrayRef<llvm::Value *>(), CRK_Unrecoverable);
- else
+ } else
Builder.CreateUnreachable();
// We do need to preserve an insertion point.
Index: tools/clang/lib/CodeGen/CodeGenFunction.cpp
===================================================================
--- tools/clang/lib/CodeGen/CodeGenFunction.cpp
+++ tools/clang/lib/CodeGen/CodeGenFunction.cpp
@@ -36,8 +36,9 @@
CodeGenFunction::CodeGenFunction(CodeGenModule &cgm, bool suppressNewContext)
: CodeGenTypeCache(cgm), CGM(cgm), Target(cgm.getTarget()),
Builder(cgm.getModule().getContext(), llvm::ConstantFolder(),
- CGBuilderInserterTy(this)), CapturedStmtInfo(nullptr),
- SanOpts(&CGM.getLangOpts().Sanitize), AutoreleaseResult(false), BlockInfo(nullptr),
+ CGBuilderInserterTy(this)),
+ CapturedStmtInfo(nullptr), SanOpts(&CGM.getLangOpts().Sanitize),
+ IsSanitizerScope(false), AutoreleaseResult(false), BlockInfo(nullptr),
BlockPointer(nullptr), LambdaThisCaptureField(nullptr),
NormalCleanupDest(nullptr), NextCleanupDestIndex(1),
FirstBlockInfo(nullptr), EHResumeBlock(nullptr), ExceptionSlot(nullptr),
@@ -843,11 +844,12 @@
// function call is used by the caller, the behavior is undefined.
if (getLangOpts().CPlusPlus && !FD->hasImplicitReturnZero() &&
!FD->getReturnType()->isVoidType() && Builder.GetInsertBlock()) {
- if (SanOpts->Return)
+ if (SanOpts->Return) {
+ SanitizerScope SanScope(this);
EmitCheck(Builder.getFalse(), "missing_return",
EmitCheckSourceLocation(FD->getLocation()),
ArrayRef<llvm::Value *>(), CRK_Unrecoverable);
- else if (CGM.getCodeGenOpts().OptimizationLevel == 0)
+ } else if (CGM.getCodeGenOpts().OptimizationLevel == 0)
Builder.CreateCall(CGM.getIntrinsic(llvm::Intrinsic::trap));
Builder.CreateUnreachable();
Builder.ClearInsertionPoint();
@@ -1499,6 +1501,7 @@
// greater than zero.
if (SanOpts->VLABound &&
size->getType()->isSignedIntegerType()) {
+ SanitizerScope SanScope(this);
llvm::Value *Zero = llvm::Constant::getNullValue(Size->getType());
llvm::Constant *StaticArgs[] = {
EmitCheckSourceLocation(size->getLocStart()),
@@ -1637,11 +1640,26 @@
CodeGenFunction::CGCapturedStmtInfo::~CGCapturedStmtInfo() { }
+CodeGenFunction::SanitizerScope::SanitizerScope(CodeGenFunction *CGF)
+ : CGF(CGF) {
+ assert(!CGF->IsSanitizerScope);
+ CGF->IsSanitizerScope = true;
+}
+
+CodeGenFunction::SanitizerScope::~SanitizerScope() {
+ CGF->IsSanitizerScope = false;
+}
+
void CodeGenFunction::InsertHelper(llvm::Instruction *I,
const llvm::Twine &Name,
llvm::BasicBlock *BB,
llvm::BasicBlock::iterator InsertPt) const {
LoopStack.InsertHelper(I);
+ if (IsSanitizerScope) {
+ I->setMetadata(
+ CGM.getModule().getMDKindID("ubsan"),
+ llvm::MDNode::get(CGM.getLLVMContext(), ArrayRef<llvm::Value *>()));
+ }
}
template <bool PreserveNames>
Index: tools/clang/test/CodeGen/catch-undef-behavior.c
===================================================================
--- tools/clang/test/CodeGen/catch-undef-behavior.c
+++ tools/clang/test/CodeGen/catch-undef-behavior.c
@@ -49,7 +49,7 @@
// CHECK-TRAP-NEXT: %[[CHECK2:.*]] = icmp eq i64 %[[MISALIGN]], 0
// CHECK: %[[OK:.*]] = and i1 %[[CHECK01]], %[[CHECK2]]
- // CHECK-NEXT: br i1 %[[OK]], {{.*}} !prof ![[WEIGHT_MD:.*]]
+ // CHECK-NEXT: br i1 %[[OK]], {{.*}} !prof ![[WEIGHT_MD:.*]], !ubsan
// CHECK-TRAP: %[[OK:.*]] = and i1 %[[CHECK01]], %[[CHECK2]]
// CHECK-TRAP-NEXT: br i1 %[[OK]], {{.*}}
@@ -311,7 +311,7 @@
// CHECK: %[[LE:.*]] = fcmp olt x86_fp80 %[[F]], 0xK401E8000000000000000
// CHECK: and i1 %[[GE]], %[[LE]]
- // CHECK: store x86_fp80 %[[F]], x86_fp80* %[[ALLOCA:.*]]
+ // CHECK: store x86_fp80 %[[F]], x86_fp80* %[[ALLOCA:.*]], !ubsan
// CHECK: %[[ARG:.*]] = ptrtoint x86_fp80* %[[ALLOCA]] to i64
// CHECK: call void @__ubsan_handle_float_cast_overflow({{.*}}, i64 %[[ARG]]
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits