ubsan: Add checking for invalid downcasts. Per [expr.static.cast]p2 and p11,

base-to-derived casts have undefined behavior if the object is not actually an
instance of the derived type.


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@175078 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Richard Smith 2013-02-13 21:18:23 +00:00
Родитель a03ab10f0e
Коммит c764830bdb
5 изменённых файлов: 88 добавлений и 5 удалений

Просмотреть файл

@ -232,7 +232,7 @@ CodeGenFunction::GetAddressOfDerivedClass(llvm::Value *Value,
QualType DerivedTy = QualType DerivedTy =
getContext().getCanonicalType(getContext().getTagDeclType(Derived)); getContext().getCanonicalType(getContext().getTagDeclType(Derived));
llvm::Type *DerivedPtrTy = ConvertType(DerivedTy)->getPointerTo(); llvm::Type *DerivedPtrTy = ConvertType(DerivedTy)->getPointerTo();
llvm::Value *NonVirtualOffset = llvm::Value *NonVirtualOffset =
CGM.GetNonVirtualBaseClassOffset(Derived, PathBegin, PathEnd); CGM.GetNonVirtualBaseClassOffset(Derived, PathBegin, PathEnd);

Просмотреть файл

@ -501,11 +501,22 @@ void CodeGenFunction::EmitTypeCheck(TypeCheckKind TCK, SourceLocation Loc,
return; return;
llvm::Value *Cond = 0; llvm::Value *Cond = 0;
llvm::BasicBlock *Done = 0;
if (SanOpts->Null) { if (SanOpts->Null) {
// The glvalue must not be an empty glvalue. // The glvalue must not be an empty glvalue.
Cond = Builder.CreateICmpNE( Cond = Builder.CreateICmpNE(
Address, llvm::Constant::getNullValue(Address->getType())); Address, llvm::Constant::getNullValue(Address->getType()));
if (TCK == TCK_DowncastPointer) {
// When performing a pointer downcast, it's OK if the value is null.
// Skip the remaining checks in that case.
Done = createBasicBlock("null");
llvm::BasicBlock *Rest = createBasicBlock("not.null");
Builder.CreateCondBr(Cond, Rest, Done);
EmitBlock(Rest);
Cond = 0;
}
} }
if (SanOpts->ObjectSize && !Ty->isIncompleteType()) { if (SanOpts->ObjectSize && !Ty->isIncompleteType()) {
@ -561,7 +572,8 @@ void CodeGenFunction::EmitTypeCheck(TypeCheckKind TCK, SourceLocation Loc,
// or call a non-static member function // or call a non-static member function
CXXRecordDecl *RD = Ty->getAsCXXRecordDecl(); CXXRecordDecl *RD = Ty->getAsCXXRecordDecl();
if (SanOpts->Vptr && if (SanOpts->Vptr &&
(TCK == TCK_MemberAccess || TCK == TCK_MemberCall) && (TCK == TCK_MemberAccess || TCK == TCK_MemberCall ||
TCK == TCK_DowncastPointer || TCK == TCK_DowncastReference) &&
RD && RD->hasDefinition() && RD->isDynamicClass()) { RD && RD->hasDefinition() && RD->isDynamicClass()) {
// Compute a hash of the mangled name of the type. // Compute a hash of the mangled name of the type.
// //
@ -611,6 +623,11 @@ void CodeGenFunction::EmitTypeCheck(TypeCheckKind TCK, SourceLocation Loc,
"dynamic_type_cache_miss", StaticData, DynamicData, "dynamic_type_cache_miss", StaticData, DynamicData,
CRK_AlwaysRecoverable); CRK_AlwaysRecoverable);
} }
if (Done) {
Builder.CreateBr(Done);
EmitBlock(Done);
}
} }
@ -2638,7 +2655,13 @@ LValue CodeGenFunction::EmitCastLValue(const CastExpr *E) {
cast<CXXRecordDecl>(DerivedClassTy->getDecl()); cast<CXXRecordDecl>(DerivedClassTy->getDecl());
LValue LV = EmitLValue(E->getSubExpr()); LValue LV = EmitLValue(E->getSubExpr());
// C++11 [expr.static.cast]p2: Behavior is undefined if a downcast is
// performed and the object is not of the derived type.
if (SanitizePerformTypeCheck)
EmitTypeCheck(TCK_DowncastReference, E->getExprLoc(),
LV.getAddress(), E->getType());
// Perform the base-to-derived conversion // Perform the base-to-derived conversion
llvm::Value *Derived = llvm::Value *Derived =
GetAddressOfDerivedClass(LV.getAddress(), DerivedClassDecl, GetAddressOfDerivedClass(LV.getAddress(), DerivedClassDecl,

Просмотреть файл

@ -1220,7 +1220,15 @@ Value *ScalarExprEmitter::VisitCastExpr(CastExpr *CE) {
const CXXRecordDecl *DerivedClassDecl = DestTy->getPointeeCXXRecordDecl(); const CXXRecordDecl *DerivedClassDecl = DestTy->getPointeeCXXRecordDecl();
assert(DerivedClassDecl && "BaseToDerived arg isn't a C++ object pointer!"); assert(DerivedClassDecl && "BaseToDerived arg isn't a C++ object pointer!");
return CGF.GetAddressOfDerivedClass(Visit(E), DerivedClassDecl, llvm::Value *V = Visit(E);
// C++11 [expr.static.cast]p11: Behavior is undefined if a downcast is
// performed and the object is not of the derived type.
if (CGF.SanitizePerformTypeCheck)
CGF.EmitTypeCheck(CodeGenFunction::TCK_DowncastPointer, CE->getExprLoc(),
V, DestTy->getPointeeType());
return CGF.GetAddressOfDerivedClass(V, DerivedClassDecl,
CE->path_begin(), CE->path_end(), CE->path_begin(), CE->path_end(),
ShouldNullCheckClassCastValue(CE)); ShouldNullCheckClassCastValue(CE));
} }

Просмотреть файл

@ -1895,7 +1895,13 @@ public:
/// Must be an object within its lifetime. /// Must be an object within its lifetime.
TCK_MemberCall, TCK_MemberCall,
/// Checking the 'this' pointer for a constructor call. /// Checking the 'this' pointer for a constructor call.
TCK_ConstructorCall TCK_ConstructorCall,
/// Checking the operand of a static_cast to a derived pointer type. Must be
/// null or an object within its lifetime.
TCK_DowncastPointer,
/// Checking the operand of a static_cast to a derived reference type. Must
/// be an object within its lifetime.
TCK_DowncastReference
}; };
/// \brief Emit a check that \p V is the address of storage of the /// \brief Emit a check that \p V is the address of storage of the

Просмотреть файл

@ -6,6 +6,8 @@ struct S {
virtual int f(); virtual int f();
}; };
struct T : S {};
// CHECK: @_Z17reference_binding // CHECK: @_Z17reference_binding
void reference_binding(int *p, S *q) { void reference_binding(int *p, S *q) {
// C++ core issue 453: If an lvalue to which a reference is directly bound // C++ core issue 453: If an lvalue to which a reference is directly bound
@ -173,3 +175,47 @@ int bad_enum_value() {
int c = e3; int c = e3;
return a + b + c; return a + b + c;
} }
// CHECK: @_Z20bad_downcast_pointer
void bad_downcast_pointer(S *p) {
// CHECK: %[[NONNULL:.*]] = icmp ne {{.*}}, null
// CHECK: br i1 %[[NONNULL]],
// CHECK: %[[SIZE:.*]] = call i64 @llvm.objectsize.i64(
// CHECK: %[[E1:.*]] = icmp uge i64 %[[SIZE]], 24
// CHECK: %[[MISALIGN:.*]] = and i64 %{{.*}}, 7
// CHECK: %[[E2:.*]] = icmp eq i64 %[[MISALIGN]], 0
// CHECK: %[[E12:.*]] = and i1 %[[E1]], %[[E2]]
// CHECK: br i1 %[[E12]],
// CHECK: call void @__ubsan_handle_type_mismatch
// CHECK: br label
// CHECK: br i1 %{{.*}},
// CHECK: call void @__ubsan_handle_dynamic_type_cache_miss
// CHECK: br label
(void) static_cast<T*>(p);
}
// CHECK: @_Z22bad_downcast_reference
void bad_downcast_reference(S &p) {
// CHECK: %[[E1:.*]] = icmp ne {{.*}}, null
// CHECK-NOT: br i1
// CHECK: %[[SIZE:.*]] = call i64 @llvm.objectsize.i64(
// CHECK: %[[E2:.*]] = icmp uge i64 %[[SIZE]], 24
// CHECK: %[[E12:.*]] = and i1 %[[E1]], %[[E2]]
// CHECK: %[[MISALIGN:.*]] = and i64 %{{.*}}, 7
// CHECK: %[[E3:.*]] = icmp eq i64 %[[MISALIGN]], 0
// CHECK: %[[E123:.*]] = and i1 %[[E12]], %[[E3]]
// CHECK: br i1 %[[E123]],
// CHECK: call void @__ubsan_handle_type_mismatch
// CHECK: br label
// CHECK: br i1 %{{.*}},
// CHECK: call void @__ubsan_handle_dynamic_type_cache_miss
// CHECK: br label
(void) static_cast<T&>(p);
}