summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--clang/lib/CodeGen/CGClass.cpp23
-rw-r--r--clang/lib/CodeGen/CGExpr.cpp24
-rw-r--r--clang/lib/CodeGen/CGExprScalar.cpp6
-rw-r--r--clang/lib/CodeGen/CodeGenFunction.h13
-rw-r--r--clang/test/CodeGenCXX/catch-undef-behavior.cpp34
-rw-r--r--compiler-rt/lib/ubsan/ubsan_handlers.cc6
-rw-r--r--compiler-rt/test/ubsan/TestCases/TypeCheck/misaligned.cpp17
-rw-r--r--compiler-rt/test/ubsan/TestCases/TypeCheck/vptr-virtual-base.cpp16
8 files changed, 112 insertions, 27 deletions
diff --git a/clang/lib/CodeGen/CGClass.cpp b/clang/lib/CodeGen/CGClass.cpp
index 49760853dc8..d7010c7e916 100644
--- a/clang/lib/CodeGen/CGClass.cpp
+++ b/clang/lib/CodeGen/CGClass.cpp
@@ -134,12 +134,11 @@ ApplyNonVirtualAndVirtualOffset(CodeGenFunction &CGF, llvm::Value *ptr,
return ptr;
}
-llvm::Value *
-CodeGenFunction::GetAddressOfBaseClass(llvm::Value *Value,
- const CXXRecordDecl *Derived,
- CastExpr::path_const_iterator PathBegin,
- CastExpr::path_const_iterator PathEnd,
- bool NullCheckValue) {
+llvm::Value *CodeGenFunction::GetAddressOfBaseClass(
+ llvm::Value *Value, const CXXRecordDecl *Derived,
+ CastExpr::path_const_iterator PathBegin,
+ CastExpr::path_const_iterator PathEnd, bool NullCheckValue,
+ SourceLocation Loc) {
assert(PathBegin != PathEnd && "Base path should not be empty!");
CastExpr::path_const_iterator Start = PathBegin;
@@ -176,9 +175,16 @@ CodeGenFunction::GetAddressOfBaseClass(llvm::Value *Value,
llvm::Type *BasePtrTy =
ConvertType((PathEnd[-1])->getType())->getPointerTo();
+ QualType DerivedTy = getContext().getRecordType(Derived);
+ CharUnits DerivedAlign = getContext().getTypeAlignInChars(DerivedTy);
+
// If the static offset is zero and we don't have a virtual step,
// just do a bitcast; null checks are unnecessary.
if (NonVirtualOffset.isZero() && !VBase) {
+ if (sanitizePerformTypeCheck()) {
+ EmitTypeCheck(TCK_Upcast, Loc, Value, DerivedTy, DerivedAlign,
+ !NullCheckValue);
+ }
return Builder.CreateBitCast(Value, BasePtrTy);
}
@@ -197,6 +203,11 @@ CodeGenFunction::GetAddressOfBaseClass(llvm::Value *Value,
EmitBlock(notNullBB);
}
+ if (sanitizePerformTypeCheck()) {
+ EmitTypeCheck(VBase ? TCK_UpcastToVirtualBase : TCK_Upcast, Loc, Value,
+ DerivedTy, DerivedAlign, true);
+ }
+
// Compute the virtual offset.
llvm::Value *VirtualOffset = nullptr;
if (VBase) {
diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp
index 54c2fd26473..b7504ca1223 100644
--- a/clang/lib/CodeGen/CGExpr.cpp
+++ b/clang/lib/CodeGen/CGExpr.cpp
@@ -377,7 +377,7 @@ LValue CodeGenFunction::EmitMaterializeTemporaryExpr(
GetAddressOfBaseClass(Object, Adjustment.DerivedToBase.DerivedClass,
Adjustment.DerivedToBase.BasePath->path_begin(),
Adjustment.DerivedToBase.BasePath->path_end(),
- /*NullCheckValue=*/ false);
+ /*NullCheckValue=*/ false, E->getExprLoc());
break;
case SubobjectAdjustment::FieldAdjustment: {
@@ -448,8 +448,8 @@ bool CodeGenFunction::sanitizePerformTypeCheck() const {
}
void CodeGenFunction::EmitTypeCheck(TypeCheckKind TCK, SourceLocation Loc,
- llvm::Value *Address,
- QualType Ty, CharUnits Alignment) {
+ llvm::Value *Address, QualType Ty,
+ CharUnits Alignment, bool SkipNullCheck) {
if (!sanitizePerformTypeCheck())
return;
@@ -464,13 +464,15 @@ void CodeGenFunction::EmitTypeCheck(TypeCheckKind TCK, SourceLocation Loc,
llvm::Value *Cond = nullptr;
llvm::BasicBlock *Done = nullptr;
- if (SanOpts->Null || TCK == TCK_DowncastPointer) {
+ bool AllowNullPointers = TCK == TCK_DowncastPointer || TCK == TCK_Upcast ||
+ TCK == TCK_UpcastToVirtualBase;
+ if ((SanOpts->Null || AllowNullPointers) && !SkipNullCheck) {
// The glvalue must not be an empty glvalue.
Cond = Builder.CreateICmpNE(
Address, llvm::Constant::getNullValue(Address->getType()));
- if (TCK == TCK_DowncastPointer) {
- // When performing a pointer downcast, it's OK if the value is null.
+ if (AllowNullPointers) {
+ // When performing pointer casts, it's OK if the value is null.
// Skip the remaining checks in that case.
Done = createBasicBlock("null");
llvm::BasicBlock *Rest = createBasicBlock("not.null");
@@ -536,7 +538,8 @@ void CodeGenFunction::EmitTypeCheck(TypeCheckKind TCK, SourceLocation Loc,
CXXRecordDecl *RD = Ty->getAsCXXRecordDecl();
if (SanOpts->Vptr &&
(TCK == TCK_MemberAccess || TCK == TCK_MemberCall ||
- TCK == TCK_DowncastPointer || TCK == TCK_DowncastReference) &&
+ TCK == TCK_DowncastPointer || TCK == TCK_DowncastReference ||
+ TCK == TCK_UpcastToVirtualBase) &&
RD && RD->hasDefinition() && RD->isDynamicClass()) {
// Compute a hash of the mangled name of the type.
//
@@ -2874,10 +2877,9 @@ LValue CodeGenFunction::EmitCastLValue(const CastExpr *E) {
llvm::Value *This = LV.getAddress();
// Perform the derived-to-base conversion
- llvm::Value *Base =
- GetAddressOfBaseClass(This, DerivedClassDecl,
- E->path_begin(), E->path_end(),
- /*NullCheckValue=*/false);
+ llvm::Value *Base = GetAddressOfBaseClass(
+ This, DerivedClassDecl, E->path_begin(), E->path_end(),
+ /*NullCheckValue=*/false, E->getExprLoc());
return MakeAddrLValue(Base, E->getType());
}
diff --git a/clang/lib/CodeGen/CGExprScalar.cpp b/clang/lib/CodeGen/CGExprScalar.cpp
index 5ca2414efa7..8d8fd39cb01 100644
--- a/clang/lib/CodeGen/CGExprScalar.cpp
+++ b/clang/lib/CodeGen/CGExprScalar.cpp
@@ -1388,9 +1388,9 @@ Value *ScalarExprEmitter::VisitCastExpr(CastExpr *CE) {
E->getType()->getPointeeCXXRecordDecl();
assert(DerivedClassDecl && "DerivedToBase arg isn't a C++ object pointer!");
- return CGF.GetAddressOfBaseClass(Visit(E), DerivedClassDecl,
- CE->path_begin(), CE->path_end(),
- ShouldNullCheckClassCastValue(CE));
+ return CGF.GetAddressOfBaseClass(
+ Visit(E), DerivedClassDecl, CE->path_begin(), CE->path_end(),
+ ShouldNullCheckClassCastValue(CE), CE->getExprLoc());
}
case CK_Dynamic: {
Value *V = Visit(const_cast<Expr*>(E));
diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h
index f20b758a3b4..865f1c9668f 100644
--- a/clang/lib/CodeGen/CodeGenFunction.h
+++ b/clang/lib/CodeGen/CodeGenFunction.h
@@ -1681,7 +1681,7 @@ public:
const CXXRecordDecl *Derived,
CastExpr::path_const_iterator PathBegin,
CastExpr::path_const_iterator PathEnd,
- bool NullCheckValue);
+ bool NullCheckValue, SourceLocation Loc);
llvm::Value *GetAddressOfDerivedClass(llvm::Value *Value,
const CXXRecordDecl *Derived,
@@ -1776,7 +1776,13 @@ public:
TCK_DowncastPointer,
/// Checking the operand of a static_cast to a derived reference type. Must
/// be an object within its lifetime.
- TCK_DowncastReference
+ TCK_DowncastReference,
+ /// Checking the operand of a cast to a base object. Must be suitably sized
+ /// and aligned.
+ TCK_Upcast,
+ /// Checking the operand of a cast to a virtual base object. Must be an
+ /// object within its lifetime.
+ TCK_UpcastToVirtualBase
};
/// \brief Whether any type-checking sanitizers are enabled. If \c false,
@@ -1786,7 +1792,8 @@ public:
/// \brief Emit a check that \p V is the address of storage of the
/// appropriate size and alignment for an object of type \p Type.
void EmitTypeCheck(TypeCheckKind TCK, SourceLocation Loc, llvm::Value *V,
- QualType Type, CharUnits Alignment = CharUnits::Zero());
+ QualType Type, CharUnits Alignment = CharUnits::Zero(),
+ bool SkipNullCheck = false);
/// \brief Emit a check that \p Base points into an array object, which
/// we can access at index \p Index. \p Accessed should be \c false if we
diff --git a/clang/test/CodeGenCXX/catch-undef-behavior.cpp b/clang/test/CodeGenCXX/catch-undef-behavior.cpp
index 333855d0ba6..5bf31c1ca40 100644
--- a/clang/test/CodeGenCXX/catch-undef-behavior.cpp
+++ b/clang/test/CodeGenCXX/catch-undef-behavior.cpp
@@ -404,6 +404,40 @@ void indirect_function_call(void (*p)(int)) {
p(42);
}
+namespace UpcastPointerTest {
+struct S {};
+struct T : S { double d; };
+struct V : virtual S {};
+
+// CHECK-LABEL: upcast_pointer
+S* upcast_pointer(T* t) {
+ // Check for null pointer
+ // CHECK: %[[NONNULL:.*]] = icmp ne {{.*}}, null
+ // CHECK: br i1 %[[NONNULL]]
+
+ // Check alignment
+ // CHECK: %[[MISALIGN:.*]] = and i64 %{{.*}}, 7
+ // CHECK: icmp eq i64 %[[MISALIGN]], 0
+
+ // CHECK: call void @__ubsan_handle_type_mismatch
+ return t;
+}
+
+V getV();
+
+// CHECK-LABEL: upcast_to_vbase
+void upcast_to_vbase() {
+ // No need to check for null here, as we have a temporary here.
+
+ // CHECK-NOT: br i1
+
+ // CHECK: call i64 @llvm.objectsize
+ // CHECK: call void @__ubsan_handle_type_mismatch
+ // CHECK: call void @__ubsan_handle_dynamic_type_cache_miss
+ const S& s = getV();
+}
+}
+
namespace CopyValueRepresentation {
// CHECK-LABEL: define {{.*}} @_ZN23CopyValueRepresentation2S3aSERKS0_
// CHECK-NOT: call {{.*}} @__ubsan_handle_load_invalid_value
diff --git a/compiler-rt/lib/ubsan/ubsan_handlers.cc b/compiler-rt/lib/ubsan/ubsan_handlers.cc
index f8365a7d2fe..a0ecff94359 100644
--- a/compiler-rt/lib/ubsan/ubsan_handlers.cc
+++ b/compiler-rt/lib/ubsan/ubsan_handlers.cc
@@ -30,10 +30,10 @@ static bool ignoreReport(SourceLocation SLoc, ReportOptions Opts) {
}
namespace __ubsan {
- const char *TypeCheckKinds[] = {
+const char *TypeCheckKinds[] = {
"load of", "store to", "reference binding to", "member access within",
- "member call on", "constructor call on", "downcast of", "downcast of"
- };
+ "member call on", "constructor call on", "downcast of", "downcast of",
+ "upcast of", "cast to virtual base of"};
}
static void handleTypeMismatchImpl(TypeMismatchData *Data, ValueHandle Pointer,
diff --git a/compiler-rt/test/ubsan/TestCases/TypeCheck/misaligned.cpp b/compiler-rt/test/ubsan/TestCases/TypeCheck/misaligned.cpp
index d5d70f2e552..79f5136db96 100644
--- a/compiler-rt/test/ubsan/TestCases/TypeCheck/misaligned.cpp
+++ b/compiler-rt/test/ubsan/TestCases/TypeCheck/misaligned.cpp
@@ -1,11 +1,12 @@
// RUN: %clangxx -fsanitize=alignment -g %s -O3 -o %t
-// RUN: %run %t l0 && %run %t s0 && %run %t r0 && %run %t m0 && %run %t f0 && %run %t n0
+// RUN: %run %t l0 && %run %t s0 && %run %t r0 && %run %t m0 && %run %t f0 && %run %t n0 && %run %t u0
// RUN: %run %t l1 2>&1 | FileCheck %s --check-prefix=CHECK-LOAD --strict-whitespace
// RUN: %run %t s1 2>&1 | FileCheck %s --check-prefix=CHECK-STORE
// RUN: %run %t r1 2>&1 | FileCheck %s --check-prefix=CHECK-REFERENCE
// RUN: %run %t m1 2>&1 | FileCheck %s --check-prefix=CHECK-MEMBER
// RUN: %run %t f1 2>&1 | FileCheck %s --check-prefix=CHECK-MEMFUN
// RUN: %run %t n1 2>&1 | FileCheck %s --check-prefix=CHECK-NEW
+// RUN: %run %t u1 2>&1 | FileCheck %s --check-prefix=CHECK-UPCAST
// RUN: UBSAN_OPTIONS=print_stacktrace=1 %run %t l1 2>&1 | FileCheck %s --check-prefix=CHECK-LOAD --check-prefix=CHECK-%os-STACK-LOAD
// RUN: %clangxx -fsanitize=alignment -fno-sanitize-recover %s -O3 -o %t
@@ -20,12 +21,17 @@ struct S {
int k;
};
+struct T : S {
+ int t;
+};
+
int main(int, char **argv) {
char c[] __attribute__((aligned(8))) = { 0, 0, 0, 0, 1, 2, 3, 4, 5 };
// Pointer value may be unspecified here, but behavior is not undefined.
int *p = (int*)&c[4 + argv[1][1] - '0'];
S *s = (S*)p;
+ T *t = (T*)p;
void *wild = reinterpret_cast<void *>(0x123L);
@@ -81,6 +87,15 @@ int main(int, char **argv) {
// CHECK-NEW-NEXT: {{^ \^}}
return (new (s) S)->k && 0;
+ case 'u': {
+ // CHECK-UPCAST: misaligned.cpp:[[@LINE+4]]:17: runtime error: upcast of misaligned address [[PTR:0x[0-9a-f]*]] for type 'T', which requires 4 byte alignment
+ // CHECK-UPCAST-NEXT: [[PTR]]: note: pointer points here
+ // CHECK-UPCAST-NEXT: {{^ 00 00 00 01 02 03 04 05}}
+ // CHECK-UPCAST-NEXT: {{^ \^}}
+ S *s2 = (S*)t;
+ return s2->f();
+ }
+
case 'w':
// CHECK-WILD: misaligned.cpp:[[@LINE+3]]:35: runtime error: member access within misaligned address 0x000000000123 for type 'S', which requires 4 byte alignment
// CHECK-WILD-NEXT: 0x000000000123: note: pointer points here
diff --git a/compiler-rt/test/ubsan/TestCases/TypeCheck/vptr-virtual-base.cpp b/compiler-rt/test/ubsan/TestCases/TypeCheck/vptr-virtual-base.cpp
new file mode 100644
index 00000000000..d5130fe23ae
--- /dev/null
+++ b/compiler-rt/test/ubsan/TestCases/TypeCheck/vptr-virtual-base.cpp
@@ -0,0 +1,16 @@
+// RUN: %clangxx -fsanitize=vptr -fno-sanitize-recover -g %s -O3 -o %t
+// RUN: not %run %t 2>&1 | FileCheck %s
+
+struct S { virtual int f() { return 0; } };
+struct T : virtual S {};
+
+struct Foo { virtual int f() { return 0; } };
+
+int main(int argc, char **argv) {
+ Foo foo;
+ T *t = (T*)&foo;
+ S *s = t;
+ // CHECK: vptr-virtual-base.cpp:[[@LINE-1]]:10: runtime error: cast to virtual base of address [[PTR:0x[0-9a-f]*]] which does not point to an object of type 'T'
+ // CHECK-NEXT: [[PTR]]: note: object is of type 'Foo'
+ return s->f();
+}
OpenPOWER on IntegriCloud