aboutsummaryrefslogtreecommitdiff
path: root/clang/lib
diff options
context:
space:
mode:
authorRoman Lebedev <lebedev.ri@gmail.com>2019-01-14 19:09:27 +0000
committerRoman Lebedev <lebedev.ri@gmail.com>2019-01-14 19:09:27 +0000
commit7892c37455d5890be86a02882381bd240661a0e1 (patch)
tree054d1e49af2c80ef4bc12b5c493ebc4d2de506f2 /clang/lib
parentc7f215dbffa6e24beb1726762f348ca62beb6bd8 (diff)
[clang][UBSan] Sanitization for alignment assumptions.
Summary: UB isn't nice. It's cool and powerful, but not nice. Having a way to detect it is nice though. [[ https://wg21.link/p1007r3 | P1007R3: std::assume_aligned ]] / http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p1007r2.pdf says: ``` We propose to add this functionality via a library function instead of a core language attribute. ... If the pointer passed in is not aligned to at least N bytes, calling assume_aligned results in undefined behaviour. ``` This differential teaches clang to sanitize all the various variants of this assume-aligned attribute. Requires D54588 for LLVM IRBuilder changes. The compiler-rt part is D54590. Reviewers: ABataev, craig.topper, vsk, rsmith, rnk, #sanitizers, erichkeane, filcab, rjmccall Reviewed By: rjmccall Subscribers: chandlerc, ldionne, EricWF, mclow.lists, cfe-commits, bkramer Tags: #sanitizers Differential Revision: https://reviews.llvm.org/D54589 llvm-svn: 351105
Diffstat (limited to 'clang/lib')
-rw-r--r--clang/lib/CodeGen/CGBuiltin.cpp8
-rw-r--r--clang/lib/CodeGen/CGCall.cpp18
-rw-r--r--clang/lib/CodeGen/CGExprScalar.cpp10
-rw-r--r--clang/lib/CodeGen/CGStmtOpenMP.cpp3
-rw-r--r--clang/lib/CodeGen/CodeGenFunction.cpp98
-rw-r--r--clang/lib/CodeGen/CodeGenFunction.h33
6 files changed, 145 insertions, 25 deletions
diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index 4c17602314e5..a718f2f19aa6 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -1904,15 +1904,17 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
return RValue::get(Result);
}
case Builtin::BI__builtin_assume_aligned: {
- Value *PtrValue = EmitScalarExpr(E->getArg(0));
+ const Expr *Ptr = E->getArg(0);
+ Value *PtrValue = EmitScalarExpr(Ptr);
Value *OffsetValue =
(E->getNumArgs() > 2) ? EmitScalarExpr(E->getArg(2)) : nullptr;
Value *AlignmentValue = EmitScalarExpr(E->getArg(1));
ConstantInt *AlignmentCI = cast<ConstantInt>(AlignmentValue);
- unsigned Alignment = (unsigned) AlignmentCI->getZExtValue();
+ unsigned Alignment = (unsigned)AlignmentCI->getZExtValue();
- EmitAlignmentAssumption(PtrValue, Alignment, OffsetValue);
+ EmitAlignmentAssumption(PtrValue, Ptr, /*The expr loc is sufficient.*/ SourceLocation(),
+ Alignment, OffsetValue);
return RValue::get(PtrValue);
}
case Builtin::BI__assume:
diff --git a/clang/lib/CodeGen/CGCall.cpp b/clang/lib/CodeGen/CGCall.cpp
index 455a25434ffb..7d494bb1f1c7 100644
--- a/clang/lib/CodeGen/CGCall.cpp
+++ b/clang/lib/CodeGen/CGCall.cpp
@@ -2410,7 +2410,10 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI,
if (!AVAttr)
if (const auto *TOTy = dyn_cast<TypedefType>(OTy))
AVAttr = TOTy->getDecl()->getAttr<AlignValueAttr>();
- if (AVAttr) {
+ if (AVAttr && !SanOpts.has(SanitizerKind::Alignment)) {
+ // If alignment-assumption sanitizer is enabled, we do *not* add
+ // alignment attribute here, but emit normal alignment assumption,
+ // so the UBSAN check could function.
llvm::Value *AlignmentValue =
EmitScalarExpr(AVAttr->getAlignment());
llvm::ConstantInt *AlignmentCI =
@@ -4535,13 +4538,14 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
llvm::Value *Alignment = EmitScalarExpr(AA->getAlignment());
llvm::ConstantInt *AlignmentCI = cast<llvm::ConstantInt>(Alignment);
- EmitAlignmentAssumption(Ret.getScalarVal(), AlignmentCI->getZExtValue(),
- OffsetValue);
+ EmitAlignmentAssumption(Ret.getScalarVal(), RetTy, Loc, AA->getLocation(),
+ AlignmentCI->getZExtValue(), OffsetValue);
} else if (const auto *AA = TargetDecl->getAttr<AllocAlignAttr>()) {
- llvm::Value *ParamVal =
- CallArgs[AA->getParamIndex().getLLVMIndex()].getRValue(
- *this).getScalarVal();
- EmitAlignmentAssumption(Ret.getScalarVal(), ParamVal);
+ llvm::Value *AlignmentVal = CallArgs[AA->getParamIndex().getLLVMIndex()]
+ .getRValue(*this)
+ .getScalarVal();
+ EmitAlignmentAssumption(Ret.getScalarVal(), RetTy, Loc, AA->getLocation(),
+ AlignmentVal);
}
}
diff --git a/clang/lib/CodeGen/CGExprScalar.cpp b/clang/lib/CodeGen/CGExprScalar.cpp
index f53bb33e463a..1c14d4c99a23 100644
--- a/clang/lib/CodeGen/CGExprScalar.cpp
+++ b/clang/lib/CodeGen/CGExprScalar.cpp
@@ -258,8 +258,11 @@ public:
AVAttr = TTy->getDecl()->getAttr<AlignValueAttr>();
} else {
// Assumptions for function parameters are emitted at the start of the
- // function, so there is no need to repeat that here.
- if (isa<ParmVarDecl>(VD))
+ // function, so there is no need to repeat that here,
+ // unless the alignment-assumption sanitizer is enabled,
+ // then we prefer the assumption over alignment attribute
+ // on IR function param.
+ if (isa<ParmVarDecl>(VD) && !CGF.SanOpts.has(SanitizerKind::Alignment))
return;
AVAttr = VD->getAttr<AlignValueAttr>();
@@ -276,7 +279,8 @@ public:
Value *AlignmentValue = CGF.EmitScalarExpr(AVAttr->getAlignment());
llvm::ConstantInt *AlignmentCI = cast<llvm::ConstantInt>(AlignmentValue);
- CGF.EmitAlignmentAssumption(V, AlignmentCI->getZExtValue());
+ CGF.EmitAlignmentAssumption(V, E, AVAttr->getLocation(),
+ AlignmentCI->getZExtValue());
}
/// EmitLoadOfLValue - Given an expression with complex type that represents a
diff --git a/clang/lib/CodeGen/CGStmtOpenMP.cpp b/clang/lib/CodeGen/CGStmtOpenMP.cpp
index 650f4e8b91aa..eb1304d89345 100644
--- a/clang/lib/CodeGen/CGStmtOpenMP.cpp
+++ b/clang/lib/CodeGen/CGStmtOpenMP.cpp
@@ -1472,7 +1472,8 @@ static void emitAlignedClause(CodeGenFunction &CGF,
"alignment is not power of 2");
if (Alignment != 0) {
llvm::Value *PtrValue = CGF.EmitScalarExpr(E);
- CGF.EmitAlignmentAssumption(PtrValue, Alignment);
+ CGF.EmitAlignmentAssumption(
+ PtrValue, E, /*No second loc needed*/ SourceLocation(), Alignment);
}
}
}
diff --git a/clang/lib/CodeGen/CodeGenFunction.cpp b/clang/lib/CodeGen/CodeGenFunction.cpp
index 2b25fb469d75..1713e40c312b 100644
--- a/clang/lib/CodeGen/CodeGenFunction.cpp
+++ b/clang/lib/CodeGen/CodeGenFunction.cpp
@@ -2207,6 +2207,49 @@ void CodeGenFunction::unprotectFromPeepholes(PeepholeProtection protection) {
protection.Inst->eraseFromParent();
}
+void CodeGenFunction::EmitAlignmentAssumption(llvm::Value *PtrValue,
+ QualType Ty, SourceLocation Loc,
+ SourceLocation AssumptionLoc,
+ llvm::Value *Alignment,
+ llvm::Value *OffsetValue) {
+ llvm::Value *TheCheck;
+ llvm::Instruction *Assumption = Builder.CreateAlignmentAssumption(
+ CGM.getDataLayout(), PtrValue, Alignment, OffsetValue, &TheCheck);
+ if (SanOpts.has(SanitizerKind::Alignment)) {
+ EmitAlignmentAssumptionCheck(PtrValue, Ty, Loc, AssumptionLoc, Alignment,
+ OffsetValue, TheCheck, Assumption);
+ }
+}
+
+void CodeGenFunction::EmitAlignmentAssumption(llvm::Value *PtrValue,
+ QualType Ty, SourceLocation Loc,
+ SourceLocation AssumptionLoc,
+ unsigned Alignment,
+ llvm::Value *OffsetValue) {
+ llvm::Value *TheCheck;
+ llvm::Instruction *Assumption = Builder.CreateAlignmentAssumption(
+ CGM.getDataLayout(), PtrValue, Alignment, OffsetValue, &TheCheck);
+ if (SanOpts.has(SanitizerKind::Alignment)) {
+ llvm::Value *AlignmentVal = llvm::ConstantInt::get(IntPtrTy, Alignment);
+ EmitAlignmentAssumptionCheck(PtrValue, Ty, Loc, AssumptionLoc, AlignmentVal,
+ OffsetValue, TheCheck, Assumption);
+ }
+}
+
+void CodeGenFunction::EmitAlignmentAssumption(llvm::Value *PtrValue,
+ const Expr *E,
+ SourceLocation AssumptionLoc,
+ unsigned Alignment,
+ llvm::Value *OffsetValue) {
+ if (auto *CE = dyn_cast<CastExpr>(E))
+ E = CE->getSubExprAsWritten();
+ QualType Ty = E->getType();
+ SourceLocation Loc = E->getExprLoc();
+
+ EmitAlignmentAssumption(PtrValue, Ty, Loc, AssumptionLoc, Alignment,
+ OffsetValue);
+}
+
llvm::Value *CodeGenFunction::EmitAnnotationCall(llvm::Value *AnnotationFn,
llvm::Value *AnnotatedVal,
StringRef AnnotationStr,
@@ -2459,6 +2502,61 @@ void CodeGenFunction::EmitMultiVersionResolver(
Builder.ClearInsertionPoint();
}
+// Loc - where the diagnostic will point, where in the source code this
+// alignment has failed.
+// SecondaryLoc - if present (will be present if sufficiently different from
+// Loc), the diagnostic will additionally point a "Note:" to this location.
+// It should be the location where the __attribute__((assume_aligned))
+// was written e.g.
+void CodeGenFunction::EmitAlignmentAssumptionCheck(
+ llvm::Value *Ptr, QualType Ty, SourceLocation Loc,
+ SourceLocation SecondaryLoc, llvm::Value *Alignment,
+ llvm::Value *OffsetValue, llvm::Value *TheCheck,
+ llvm::Instruction *Assumption) {
+ assert(Assumption && isa<llvm::CallInst>(Assumption) &&
+ cast<llvm::CallInst>(Assumption)->getCalledValue() ==
+ llvm::Intrinsic::getDeclaration(
+ Builder.GetInsertBlock()->getParent()->getParent(),
+ llvm::Intrinsic::assume) &&
+ "Assumption should be a call to llvm.assume().");
+ assert(&(Builder.GetInsertBlock()->back()) == Assumption &&
+ "Assumption should be the last instruction of the basic block, "
+ "since the basic block is still being generated.");
+
+ if (!SanOpts.has(SanitizerKind::Alignment))
+ return;
+
+ // Don't check pointers to volatile data. The behavior here is implementation-
+ // defined.
+ if (Ty->getPointeeType().isVolatileQualified())
+ return;
+
+ // We need to temorairly remove the assumption so we can insert the
+ // sanitizer check before it, else the check will be dropped by optimizations.
+ Assumption->removeFromParent();
+
+ {
+ SanitizerScope SanScope(this);
+
+ if (!OffsetValue)
+ OffsetValue = Builder.getInt1(0); // no offset.
+
+ llvm::Constant *StaticData[] = {EmitCheckSourceLocation(Loc),
+ EmitCheckSourceLocation(SecondaryLoc),
+ EmitCheckTypeDescriptor(Ty)};
+ llvm::Value *DynamicData[] = {EmitCheckValue(Ptr),
+ EmitCheckValue(Alignment),
+ EmitCheckValue(OffsetValue)};
+ EmitCheck({std::make_pair(TheCheck, SanitizerKind::Alignment)},
+ SanitizerHandler::AlignmentAssumption, StaticData, DynamicData);
+ }
+
+ // We are now in the (new, empty) "cont" basic block.
+ // Reintroduce the assumption.
+ Builder.Insert(Assumption);
+ // FIXME: Assumption still has it's original basic block as it's Parent.
+}
+
llvm::DebugLoc CodeGenFunction::SourceLocToDebugLoc(SourceLocation Location) {
if (CGDebugInfo *DI = getDebugInfo())
return DI->SourceLocToDebugLoc(Location);
diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h
index c8b300236f45..89cb850ab1b1 100644
--- a/clang/lib/CodeGen/CodeGenFunction.h
+++ b/clang/lib/CodeGen/CodeGenFunction.h
@@ -131,6 +131,7 @@ enum TypeEvaluationKind {
SANITIZER_CHECK(ShiftOutOfBounds, shift_out_of_bounds, 0) \
SANITIZER_CHECK(SubOverflow, sub_overflow, 0) \
SANITIZER_CHECK(TypeMismatch, type_mismatch, 1) \
+ SANITIZER_CHECK(AlignmentAssumption, alignment_assumption, 0) \
SANITIZER_CHECK(VLABoundNotPositive, vla_bound_not_positive, 0)
enum SanitizerHandler {
@@ -2633,12 +2634,6 @@ public:
ComplexPairTy EmitComplexPrePostIncDec(const UnaryOperator *E, LValue LV,
bool isInc, bool isPre);
- void EmitAlignmentAssumption(llvm::Value *PtrValue, unsigned Alignment,
- llvm::Value *OffsetValue = nullptr) {
- Builder.CreateAlignmentAssumption(CGM.getDataLayout(), PtrValue, Alignment,
- OffsetValue);
- }
-
/// Converts Location to a DebugLoc, if debug information is enabled.
llvm::DebugLoc SourceLocToDebugLoc(SourceLocation Location);
@@ -2802,11 +2797,27 @@ public:
PeepholeProtection protectFromPeepholes(RValue rvalue);
void unprotectFromPeepholes(PeepholeProtection protection);
- void EmitAlignmentAssumption(llvm::Value *PtrValue, llvm::Value *Alignment,
- llvm::Value *OffsetValue = nullptr) {
- Builder.CreateAlignmentAssumption(CGM.getDataLayout(), PtrValue, Alignment,
- OffsetValue);
- }
+ void EmitAlignmentAssumptionCheck(llvm::Value *Ptr, QualType Ty,
+ SourceLocation Loc,
+ SourceLocation AssumptionLoc,
+ llvm::Value *Alignment,
+ llvm::Value *OffsetValue,
+ llvm::Value *TheCheck,
+ llvm::Instruction *Assumption);
+
+ void EmitAlignmentAssumption(llvm::Value *PtrValue, QualType Ty,
+ SourceLocation Loc, SourceLocation AssumptionLoc,
+ llvm::Value *Alignment,
+ llvm::Value *OffsetValue = nullptr);
+
+ void EmitAlignmentAssumption(llvm::Value *PtrValue, QualType Ty,
+ SourceLocation Loc, SourceLocation AssumptionLoc,
+ unsigned Alignment,
+ llvm::Value *OffsetValue = nullptr);
+
+ void EmitAlignmentAssumption(llvm::Value *PtrValue, const Expr *E,
+ SourceLocation AssumptionLoc, unsigned Alignment,
+ llvm::Value *OffsetValue = nullptr);
//===--------------------------------------------------------------------===//
// Statement Emission