<div style="font-family: arial, helvetica, sans-serif; font-size: 10pt"><br><br><div class="gmail_quote">On Tue, Dec 18, 2012 at 1:30 PM, Richard Smith <span dir="ltr"><<a href="mailto:richard-llvm@metafoo.co.uk" target="_blank">richard-llvm@metafoo.co.uk</a>></span> wrote:<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Author: rsmith<br>
Date: Tue Dec 18 03:30:21 2012<br>
New Revision: 170423<br>
<br>
URL: <a href="http://llvm.org/viewvc/llvm-project?rev=170423&view=rev" target="_blank">http://llvm.org/viewvc/llvm-project?rev=170423&view=rev</a><br>
Log:<br>
ubsan: Demangle class names, and be more informative when a reinterpret_cast<br>
has got us to the wrong offset within an object.<br>
<br>
Modified:<br>
compiler-rt/trunk/lib/ubsan/lit_tests/TypeCheck/vptr.cpp<br>
compiler-rt/trunk/lib/ubsan/ubsan_diag.cc<br>
compiler-rt/trunk/lib/ubsan/ubsan_diag.h<br>
compiler-rt/trunk/lib/ubsan/ubsan_handlers_cxx.cc<br>
compiler-rt/trunk/lib/ubsan/ubsan_type_hash.cc<br>
compiler-rt/trunk/lib/ubsan/ubsan_type_hash.h<br>
<br>
Modified: compiler-rt/trunk/lib/ubsan/lit_tests/TypeCheck/vptr.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/ubsan/lit_tests/TypeCheck/vptr.cpp?rev=170423&r1=170422&r2=170423&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/ubsan/lit_tests/TypeCheck/vptr.cpp?rev=170423&r1=170422&r2=170423&view=diff</a><br>
==============================================================================<br>
--- compiler-rt/trunk/lib/ubsan/lit_tests/TypeCheck/vptr.cpp (original)<br>
+++ compiler-rt/trunk/lib/ubsan/lit_tests/TypeCheck/vptr.cpp Tue Dec 18 03:30:21 2012<br>
@@ -75,7 +75,7 @@<br>
<br>
case 'm':<br>
// CHECK-MEMBER: vptr.cpp:[[@LINE+5]]:15: runtime error: member access within address [[PTR:0x[0-9a-f]*]] which does not point to an object of type 'T'<br>
- // CHECK-MEMBER-NEXT: [[PTR]]: note: object is of type [[DYN_TYPE:1S|1U]]<br>
+ // CHECK-MEMBER-NEXT: [[PTR]]: note: object is of type [[DYN_TYPE:'S'|'U']]<br>
// CHECK-MEMBER-NEXT: {{^ .. .. .. .. .. .. .. .. .. .. .. .. }}<br>
// CHECK-MEMBER-NEXT: {{^ \^~~~~~~~~~~(~~~~~~~~~~~~)? *$}}<br>
// CHECK-MEMBER-NEXT: {{^ vptr for}} [[DYN_TYPE]]<br>
@@ -89,7 +89,7 @@<br>
<br>
case 'f':<br>
// CHECK-MEMFUN: vptr.cpp:[[@LINE+5]]:12: runtime error: member call on address [[PTR:0x[0-9a-f]*]] which does not point to an object of type 'T'<br>
- // CHECK-MEMFUN-NEXT: [[PTR]]: note: object is of type [[DYN_TYPE:1S|1U]]<br>
+ // CHECK-MEMFUN-NEXT: [[PTR]]: note: object is of type [[DYN_TYPE:'S'|'U']]<br>
// CHECK-MEMFUN-NEXT: {{^ .. .. .. .. .. .. .. .. .. .. .. .. }}<br>
// CHECK-MEMFUN-NEXT: {{^ \^~~~~~~~~~~(~~~~~~~~~~~~)? *$}}<br>
// CHECK-MEMFUN-NEXT: {{^ vptr for}} [[DYN_TYPE]]<br>
@@ -97,10 +97,10 @@<br>
<br>
case 'o':<br>
// CHECK-OFFSET: vptr.cpp:[[@LINE+5]]:12: runtime error: member call on address [[PTR:0x[0-9a-f]*]] which does not point to an object of type 'U'<br>
- // CHECK-OFFSET-NEXT: 0x{{[0-9a-f]*}}: note: object is base class subobject at offset {{8|16}} within object of type [[DYN_TYPE:1U]]<br>
+ // CHECK-OFFSET-NEXT: 0x{{[0-9a-f]*}}: note: object is base class subobject at offset {{8|16}} within object of type [[DYN_TYPE:'U']]<br>
// CHECK-OFFSET-NEXT: {{^ .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. }}<br>
// CHECK-OFFSET-NEXT: {{^ \^ ( ~~~~~~~~~~~~)~~~~~~~~~~~ *$}}<br>
- // CHECK-OFFSET-NEXT: {{^ ( )?vptr for}} [[DYN_TYPE]]<br>
+ // CHECK-OFFSET-NEXT: {{^ ( )?vptr for}} 'T' base class of [[DYN_TYPE]]<br>
return reinterpret_cast<U*>(p)->v() - 2;<br>
}<br>
}<br>
<br>
Modified: compiler-rt/trunk/lib/ubsan/ubsan_diag.cc<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/ubsan/ubsan_diag.cc?rev=170423&r1=170422&r2=170423&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/ubsan/ubsan_diag.cc?rev=170423&r1=170422&r2=170423&view=diff</a><br>
==============================================================================<br>
--- compiler-rt/trunk/lib/ubsan/ubsan_diag.cc (original)<br>
+++ compiler-rt/trunk/lib/ubsan/ubsan_diag.cc Tue Dec 18 03:30:21 2012<br>
@@ -54,7 +54,7 @@<br>
return *this;<br>
}<br>
<br>
-/// Hexadecimal printing for numbers too large for fprintf to handle directly.<br>
+/// Hexadecimal printing for numbers too large for Printf to handle directly.<br>
static void PrintHex(UIntMax Val) {<br>
#if HAVE_INT128_T<br>
Printf("0x%08x%08x%08x%08x",<br>
@@ -93,6 +93,15 @@<br>
}<br>
}<br>
<br>
+// C++ demangling function, as required by Itanium C++ ABI. This is weak,<br>
+// because we do not require a C++ ABI library to be linked to a program<br>
+// using UBSan; if it's not present, we'll just print the string mangled.<br>
+namespace __cxxabiv1 {<br>
+ extern "C" char *__cxa_demangle(const char *mangled, char *buffer,<br>
+ size_t *length, int *status)<br>
+ __attribute__((weak));<br>
+}<br></blockquote><div><br></div><div>Do you think we should hoist (optional) demangling to sanitizer_common</div><div>and make it more portable (e.g. declare __cxa_demangle on Linux only,</div><div>use WEAK macro instead of attribute etc.)?</div>
<div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
+<br>
static void renderText(const char *Message, const Diag::Arg *Args) {<br>
for (const char *Msg = Message; *Msg; ++Msg) {<br>
if (*Msg != '%') {<br>
@@ -109,6 +118,20 @@<br>
case Diag::AK_String:<br>
Printf("%s", A.String);<br>
break;<br>
+ case Diag::AK_Mangled: {<br>
+ const char *String = 0;<br>
+ // FIXME: __cxa_demangle aggressively insists on allocating memory.<br>
+ // There's not much we can do about that, short of providing our<br>
+ // own demangler (libc++abi's implementation could easily be made<br>
+ // to not allocate). For now, we just call it anyway, and we leak<br>
+ // the returned value.<br>
+ if (__cxxabiv1::__cxa_demangle)<br>
+ String = __cxxabiv1::__cxa_demangle(A.String, 0, 0, 0);<br>
+ RawWrite("'");<br>
+ RawWrite(String ? String : A.String);<br>
+ RawWrite("'");<br>
+ break;<br>
+ }<br>
case Diag::AK_SInt:<br>
// 'long long' is guaranteed to be at least 64 bits wide.<br>
if (A.SInt >= INT64_MIN && A.SInt <= INT64_MAX)<br>
<br>
Modified: compiler-rt/trunk/lib/ubsan/ubsan_diag.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/ubsan/ubsan_diag.h?rev=170423&r1=170422&r2=170423&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/ubsan/ubsan_diag.h?rev=170423&r1=170422&r2=170423&view=diff</a><br>
==============================================================================<br>
--- compiler-rt/trunk/lib/ubsan/ubsan_diag.h (original)<br>
+++ compiler-rt/trunk/lib/ubsan/ubsan_diag.h Tue Dec 18 03:30:21 2012<br>
@@ -100,6 +100,14 @@<br>
const char *getText() const { return Text; }<br>
};<br>
<br>
+/// \brief A mangled C++ name. Really just a strong typedef for 'const char*'.<br>
+class MangledName {<br>
+ const char *Name;<br>
+public:<br>
+ MangledName(const char *Name) : Name(Name) {}<br>
+ const char *getName() const { return Name; }<br>
+};<br>
+<br>
/// \brief Representation of an in-flight diagnostic.<br>
///<br>
/// Temporary \c Diag instances are created by the handler routines to<br>
@@ -120,6 +128,7 @@<br>
/// Kinds of arguments, corresponding to members of \c Arg's union.<br>
enum ArgKind {<br>
AK_String, ///< A string argument, displayed as-is.<br>
+ AK_Mangled,///< A C++ mangled name, demangled before display.<br>
AK_UInt, ///< An unsigned integer argument.<br>
AK_SInt, ///< A signed integer argument.<br>
AK_Float, ///< A floating-point argument.<br>
@@ -130,6 +139,7 @@<br>
struct Arg {<br>
Arg() {}<br>
Arg(const char *String) : Kind(AK_String), String(String) {}<br>
+ Arg(MangledName MN) : Kind(AK_Mangled), String(MN.getName()) {}<br>
Arg(UIntMax UInt) : Kind(AK_UInt), UInt(UInt) {}<br>
Arg(SIntMax SInt) : Kind(AK_SInt), SInt(SInt) {}<br>
Arg(FloatMax Float) : Kind(AK_Float), Float(Float) {}<br>
@@ -179,6 +189,7 @@<br>
~Diag();<br>
<br>
Diag &operator<<(const char *Str) { return AddArg(Str); }<br>
+ Diag &operator<<(MangledName MN) { return AddArg(MN); }<br>
Diag &operator<<(unsigned long long V) { return AddArg(UIntMax(V)); }<br>
Diag &operator<<(const void *V) { return AddArg(V); }<br>
Diag &operator<<(const TypeDescriptor &V);<br>
<br>
Modified: compiler-rt/trunk/lib/ubsan/ubsan_handlers_cxx.cc<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/ubsan/ubsan_handlers_cxx.cc?rev=170423&r1=170422&r2=170423&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/ubsan/ubsan_handlers_cxx.cc?rev=170423&r1=170422&r2=170423&view=diff</a><br>
==============================================================================<br>
--- compiler-rt/trunk/lib/ubsan/ubsan_handlers_cxx.cc (original)<br>
+++ compiler-rt/trunk/lib/ubsan/ubsan_handlers_cxx.cc Tue Dec 18 03:30:21 2012<br>
@@ -42,17 +42,20 @@<br>
DynamicTypeInfo DTI = getDynamicTypeInfo((void*)Pointer);<br>
if (!DTI.isValid())<br>
Diag(Pointer, DL_Note, "object has invalid vptr")<br>
- << DTI.getMostDerivedTypeName()<br>
+ << MangledName(DTI.getMostDerivedTypeName())<br>
<< Range(Pointer, Pointer + sizeof(uptr), "invalid vptr");<br>
else if (!DTI.getOffset())<br>
Diag(Pointer, DL_Note, "object is of type %0")<br>
- << DTI.getMostDerivedTypeName()<br>
+ << MangledName(DTI.getMostDerivedTypeName())<br>
<< Range(Pointer, Pointer + sizeof(uptr), "vptr for %0");<br>
else<br>
+ // FIXME: Find the type at the specified offset, and include that<br>
+ // in the note.<br>
Diag(Pointer - DTI.getOffset(), DL_Note,<br>
"object is base class subobject at offset %0 within object of type %1")<br>
- << DTI.getOffset() << DTI.getMostDerivedTypeName()<br>
- << Range(Pointer, Pointer + sizeof(uptr), "vptr for %1");<br>
+ << DTI.getOffset() << MangledName(DTI.getMostDerivedTypeName())<br>
+ << MangledName(DTI.getSubobjectTypeName())<br>
+ << Range(Pointer, Pointer + sizeof(uptr), "vptr for %2 base class of %1");<br>
<br>
if (Abort)<br>
Die();<br>
<br>
Modified: compiler-rt/trunk/lib/ubsan/ubsan_type_hash.cc<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/ubsan/ubsan_type_hash.cc?rev=170423&r1=170422&r2=170423&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/ubsan/ubsan_type_hash.cc?rev=170423&r1=170422&r2=170423&view=diff</a><br>
==============================================================================<br>
--- compiler-rt/trunk/lib/ubsan/ubsan_type_hash.cc (original)<br>
+++ compiler-rt/trunk/lib/ubsan/ubsan_type_hash.cc Tue Dec 18 03:30:21 2012<br>
@@ -129,7 +129,7 @@<br>
// No base class subobjects.<br>
return false;<br>
<br>
- // Look for a zero-offset base class which is derived from \p Base.<br>
+ // Look for a base class which is derived from \p Base at the right offset.<br>
for (unsigned int base = 0; base != VTI->base_count; ++base) {<br>
// FIXME: Curtail the recursion if this base can't possibly contain the<br>
// given offset.<br>
@@ -149,6 +149,39 @@<br>
return false;<br>
}<br>
<br>
+/// \brief Find the derived-most dynamic base class of \p Derived at offset<br>
+/// \p Offset.<br>
+static const abi::__class_type_info *findBaseAtOffset(<br>
+ const abi::__class_type_info *Derived, sptr Offset) {<br>
+ if (!Offset)<br>
+ return Derived;<br>
+<br>
+ if (const abi::__si_class_type_info *SI =<br>
+ dynamic_cast<const abi::__si_class_type_info*>(Derived))<br>
+ return findBaseAtOffset(SI->__base_type, Offset);<br>
+<br>
+ const abi::__vmi_class_type_info *VTI =<br>
+ dynamic_cast<const abi::__vmi_class_type_info*>(Derived);<br>
+ if (!VTI)<br>
+ // No base class subobjects.<br>
+ return 0;<br>
+<br>
+ for (unsigned int base = 0; base != VTI->base_count; ++base) {<br>
+ sptr OffsetHere = VTI->base_info[base].__offset_flags >><br>
+ abi::__base_class_type_info::__offset_shift;<br>
+ if (VTI->base_info[base].__offset_flags &<br>
+ abi::__base_class_type_info::__virtual_mask)<br>
+ // FIXME: Can't handle virtual bases yet.<br>
+ continue;<br>
+ if (const abi::__class_type_info *Base =<br>
+ findBaseAtOffset(VTI->base_info[base].__base_type,<br>
+ Offset - OffsetHere))<br>
+ return Base;<br>
+ }<br>
+<br>
+ return 0;<br>
+}<br>
+<br>
namespace {<br>
<br>
struct VtablePrefix {<br>
@@ -206,6 +239,10 @@<br>
__ubsan::DynamicTypeInfo __ubsan::getDynamicTypeInfo(void *Object) {<br>
VtablePrefix *Vtable = getVtablePrefix(Object);<br>
if (!Vtable)<br>
- return DynamicTypeInfo(0, 0);<br>
- return DynamicTypeInfo(Vtable->TypeInfo->__type_name, -Vtable->Offset);<br>
+ return DynamicTypeInfo(0, 0, 0);<br>
+ const abi::__class_type_info *ObjectType = findBaseAtOffset(<br>
+ static_cast<const abi::__class_type_info*>(Vtable->TypeInfo),<br>
+ -Vtable->Offset);<br>
+ return DynamicTypeInfo(Vtable->TypeInfo->__type_name, -Vtable->Offset,<br>
+ ObjectType ? ObjectType->__type_name : "<unknown>");<br>
}<br>
<br>
Modified: compiler-rt/trunk/lib/ubsan/ubsan_type_hash.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/ubsan/ubsan_type_hash.h?rev=170423&r1=170422&r2=170423&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/ubsan/ubsan_type_hash.h?rev=170423&r1=170422&r2=170423&view=diff</a><br>
==============================================================================<br>
--- compiler-rt/trunk/lib/ubsan/ubsan_type_hash.h (original)<br>
+++ compiler-rt/trunk/lib/ubsan/ubsan_type_hash.h Tue Dec 18 03:30:21 2012<br>
@@ -24,10 +24,11 @@<br>
class DynamicTypeInfo {<br>
const char *MostDerivedTypeName;<br>
sptr Offset;<br>
+ const char *SubobjectTypeName;<br>
<br>
public:<br>
- DynamicTypeInfo(const char *MDTN, sptr Offset)<br>
- : MostDerivedTypeName(MDTN), Offset(Offset) {}<br>
+ DynamicTypeInfo(const char *MDTN, sptr Offset, const char *STN)<br>
+ : MostDerivedTypeName(MDTN), Offset(Offset), SubobjectTypeName(STN) {}<br>
<br>
/// Determine whether the object had a valid dynamic type.<br>
bool isValid() const { return MostDerivedTypeName; }<br>
@@ -35,6 +36,8 @@<br>
const char *getMostDerivedTypeName() const { return MostDerivedTypeName; }<br>
/// Get the offset from the most-derived type to this base class.<br>
sptr getOffset() const { return Offset; }<br>
+ /// Get the name of the most-derived type at the specified offset.<br>
+ const char *getSubobjectTypeName() const { return SubobjectTypeName; }<br>
};<br>
<br>
/// \brief Get information about the dynamic type of an object.<br>
<br>
<br>
_______________________________________________<br>
llvm-commits mailing list<br>
<a href="mailto:llvm-commits@cs.uiuc.edu">llvm-commits@cs.uiuc.edu</a><br>
<a href="http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits" target="_blank">http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits</a><br>
</blockquote></div><br><br clear="all"><div><br></div>-- <br><div>Alexey Samsonov, MSK</div><br>
</div>