[compiler-rt] r271560 - UBSan: crash less often on corrupted Vtables.
Ivan Krasin via llvm-commits
llvm-commits at lists.llvm.org
Thu Jun 2 11:36:12 PDT 2016
Author: krasin
Date: Thu Jun 2 13:36:12 2016
New Revision: 271560
URL: http://llvm.org/viewvc/llvm-project?rev=271560&view=rev
Log:
UBSan: crash less often on corrupted Vtables.
Summary:
This CL adds a weak check for a Vtable prefix: for a well-formed
Vtable, we require the prefix to be within [-1<<20; 1<<20].
Practically, this solves most of the known cases when UBSan segfaults
without providing any useful diagnostics.
Reviewers: pcc
Subscribers: kubabrecka
Differential Revision: http://reviews.llvm.org/D19750
Added:
compiler-rt/trunk/test/ubsan/TestCases/TypeCheck/vptr-corrupted-vtable-itanium.cpp
Modified:
compiler-rt/trunk/lib/ubsan/ubsan_handlers_cxx.cc
compiler-rt/trunk/lib/ubsan/ubsan_type_hash.h
compiler-rt/trunk/lib/ubsan/ubsan_type_hash_itanium.cc
Modified: compiler-rt/trunk/lib/ubsan/ubsan_handlers_cxx.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/ubsan/ubsan_handlers_cxx.cc?rev=271560&r1=271559&r2=271560&view=diff
==============================================================================
--- compiler-rt/trunk/lib/ubsan/ubsan_handlers_cxx.cc (original)
+++ compiler-rt/trunk/lib/ubsan/ubsan_handlers_cxx.cc Thu Jun 2 13:36:12 2016
@@ -55,11 +55,17 @@ static bool HandleDynamicTypeCacheMiss(
<< TypeCheckKinds[Data->TypeCheckKind] << (void*)Pointer << Data->Type;
// If possible, say what type it actually points to.
- if (!DTI.isValid())
- Diag(Pointer, DL_Note, "object has invalid vptr")
- << TypeName(DTI.getMostDerivedTypeName())
- << Range(Pointer, Pointer + sizeof(uptr), "invalid vptr");
- else if (!DTI.getOffset())
+ if (!DTI.isValid()) {
+ if (DTI.getOffset() < -VptrMaxOffsetToTop || DTI.getOffset() > VptrMaxOffsetToTop) {
+ Diag(Pointer, DL_Note, "object has a possibly invalid vptr: abs(offset to top) too big")
+ << TypeName(DTI.getMostDerivedTypeName())
+ << Range(Pointer, Pointer + sizeof(uptr), "possibly invalid vptr");
+ } else {
+ Diag(Pointer, DL_Note, "object has invalid vptr")
+ << TypeName(DTI.getMostDerivedTypeName())
+ << Range(Pointer, Pointer + sizeof(uptr), "invalid vptr");
+ }
+ } else if (!DTI.getOffset())
Diag(Pointer, DL_Note, "object is of type %0")
<< TypeName(DTI.getMostDerivedTypeName())
<< Range(Pointer, Pointer + sizeof(uptr), "vptr for %0");
Modified: compiler-rt/trunk/lib/ubsan/ubsan_type_hash.h
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/ubsan/ubsan_type_hash.h?rev=271560&r1=271559&r2=271560&view=diff
==============================================================================
--- compiler-rt/trunk/lib/ubsan/ubsan_type_hash.h (original)
+++ compiler-rt/trunk/lib/ubsan/ubsan_type_hash.h Thu Jun 2 13:36:12 2016
@@ -53,6 +53,10 @@ bool checkDynamicType(void *Object, void
const unsigned VptrTypeCacheSize = 128;
+/// A sanity check for Vtable. Offsets to top must be reasonably small
+/// numbers (by absolute value). It's a weak check for Vtable corruption.
+const int VptrMaxOffsetToTop = 1<<20;
+
/// \brief A cache of the results of checkDynamicType. \c checkDynamicType would
/// return \c true (modulo hash collisions) if
/// \code
Modified: compiler-rt/trunk/lib/ubsan/ubsan_type_hash_itanium.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/ubsan/ubsan_type_hash_itanium.cc?rev=271560&r1=271559&r2=271560&view=diff
==============================================================================
--- compiler-rt/trunk/lib/ubsan/ubsan_type_hash_itanium.cc (original)
+++ compiler-rt/trunk/lib/ubsan/ubsan_type_hash_itanium.cc Thu Jun 2 13:36:12 2016
@@ -221,6 +221,10 @@ bool __ubsan::checkDynamicType(void *Obj
VtablePrefix *Vtable = getVtablePrefix(VtablePtr);
if (!Vtable)
return false;
+ if (Vtable->Offset < -VptrMaxOffsetToTop || Vtable->Offset > VptrMaxOffsetToTop) {
+ // Too large or too small offset are signs of Vtable corruption.
+ return false;
+ }
// Check that this is actually a type_info object for a class type.
abi::__class_type_info *Derived =
@@ -243,6 +247,8 @@ __ubsan::getDynamicTypeInfoFromVtable(vo
VtablePrefix *Vtable = getVtablePrefix(VtablePtr);
if (!Vtable)
return DynamicTypeInfo(0, 0, 0);
+ if (Vtable->Offset < -VptrMaxOffsetToTop || Vtable->Offset > VptrMaxOffsetToTop)
+ return DynamicTypeInfo(0, Vtable->Offset, 0);
const abi::__class_type_info *ObjectType = findBaseAtOffset(
static_cast<const abi::__class_type_info*>(Vtable->TypeInfo),
-Vtable->Offset);
Added: compiler-rt/trunk/test/ubsan/TestCases/TypeCheck/vptr-corrupted-vtable-itanium.cpp
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/test/ubsan/TestCases/TypeCheck/vptr-corrupted-vtable-itanium.cpp?rev=271560&view=auto
==============================================================================
--- compiler-rt/trunk/test/ubsan/TestCases/TypeCheck/vptr-corrupted-vtable-itanium.cpp (added)
+++ compiler-rt/trunk/test/ubsan/TestCases/TypeCheck/vptr-corrupted-vtable-itanium.cpp Thu Jun 2 13:36:12 2016
@@ -0,0 +1,41 @@
+// RUN: %clangxx -frtti -fsanitize=vptr -fno-sanitize-recover=vptr -g %s -O3 -o %t
+// RUN: not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-CORRUPTED-VTABLE --strict-whitespace
+
+// UNSUPPORTED: win32
+// REQUIRES: stable-runtime, cxxabi
+#include <cstddef>
+
+#include <typeinfo>
+
+struct S {
+ S() {}
+ ~S() {}
+ virtual int v() { return 0; }
+};
+
+// See the proper definition in ubsan_type_hash_itanium.cc
+struct VtablePrefix {
+ signed long Offset;
+ std::type_info *TypeInfo;
+};
+
+int main(int argc, char **argv) {
+ // Test that we don't crash on corrupted vtable when
+ // offset is too large or too small.
+ S Obj;
+ void *Ptr = &Obj;
+ VtablePrefix* RealPrefix = reinterpret_cast<VtablePrefix*>(
+ *reinterpret_cast<void**>(Ptr)) - 1;
+
+ VtablePrefix Prefix[2];
+ Prefix[0].Offset = 1<<21; // Greater than VptrMaxOffset
+ Prefix[0].TypeInfo = RealPrefix->TypeInfo;
+
+ // Hack Vtable ptr for Obj.
+ *reinterpret_cast<void**>(Ptr) = static_cast<void*>(&Prefix[1]);
+
+ // CHECK-CORRUPTED-VTABLE: vptr-corrupted-vtable-itanium.cpp:[[@LINE+3]]:16: runtime error: member call on address [[PTR:0x[0-9a-f]*]] which does not point to an object of type 'S'
+ // CHECK-CORRUPTED-VTABLE-NEXT: [[PTR]]: note: object has a possibly invalid vptr: abs(offset to top) too big
+ S* Ptr2 = reinterpret_cast<S*>(Ptr);
+ return Ptr2->v();
+}
More information about the llvm-commits
mailing list