[llvm-commits] [compiler-rt] r170415 - in /compiler-rt/trunk/lib/ubsan: lit_tests/TypeCheck/misaligned.cpp lit_tests/TypeCheck/vptr.cpp ubsan_diag.cc ubsan_diag.h ubsan_handlers.cc ubsan_handlers_cxx.cc ubsan_type_hash.cc ubsan_type_hash.h

Richard Smith richard-llvm at metafoo.co.uk
Mon Dec 17 22:30:32 PST 2012


Author: rsmith
Date: Tue Dec 18 00:30:32 2012
New Revision: 170415

URL: http://llvm.org/viewvc/llvm-project?rev=170415&view=rev
Log:
ubsan: When diagnosing something wrong somewhere in memory, emit a note
pointing at the bad location and a snippet of nearby memory values. This is
strictly best-effort; reading these bytes to display the note could lead to a
seg fault, and that's explicitly OK.

Modified:
    compiler-rt/trunk/lib/ubsan/lit_tests/TypeCheck/misaligned.cpp
    compiler-rt/trunk/lib/ubsan/lit_tests/TypeCheck/vptr.cpp
    compiler-rt/trunk/lib/ubsan/ubsan_diag.cc
    compiler-rt/trunk/lib/ubsan/ubsan_diag.h
    compiler-rt/trunk/lib/ubsan/ubsan_handlers.cc
    compiler-rt/trunk/lib/ubsan/ubsan_handlers_cxx.cc
    compiler-rt/trunk/lib/ubsan/ubsan_type_hash.cc
    compiler-rt/trunk/lib/ubsan/ubsan_type_hash.h

Modified: compiler-rt/trunk/lib/ubsan/lit_tests/TypeCheck/misaligned.cpp
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/ubsan/lit_tests/TypeCheck/misaligned.cpp?rev=170415&r1=170414&r2=170415&view=diff
==============================================================================
--- compiler-rt/trunk/lib/ubsan/lit_tests/TypeCheck/misaligned.cpp (original)
+++ compiler-rt/trunk/lib/ubsan/lit_tests/TypeCheck/misaligned.cpp Tue Dec 18 00:30:32 2012
@@ -1,6 +1,6 @@
 // RUN: %clang -fsanitize=alignment %s -O3 -o %t
 // RUN: %t l0 && %t s0 && %t r0 && %t m0 && %t f0 && %t n0
-// RUN: %t l1 2>&1 | FileCheck %s --check-prefix=CHECK-LOAD
+// RUN: %t l1 2>&1 | FileCheck %s --check-prefix=CHECK-LOAD --strict-whitespace
 // RUN: %t s1 2>&1 | FileCheck %s --check-prefix=CHECK-STORE
 // RUN: %t r1 2>&1 | FileCheck %s --check-prefix=CHECK-REFERENCE
 // RUN: %t m1 2>&1 | FileCheck %s --check-prefix=CHECK-MEMBER
@@ -16,35 +16,58 @@
 };
 
 int main(int, char **argv) {
-  char c[5] __attribute__((aligned(4))) = {};
+  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[argv[1][1] - '0'];
+  int *p = (int*)&c[4 + argv[1][1] - '0'];
   S *s = (S*)p;
 
   (void)*p; // ok!
 
   switch (argv[1][0]) {
   case 'l':
-    // CHECK-LOAD: misaligned.cpp:[[@LINE+1]]:12: runtime error: load of misaligned address 0x{{[0-9a-f]*}} for type 'int', which requires 4 byte alignment
-    return *p;
+    // CHECK-LOAD: misaligned.cpp:[[@LINE+4]]:12: runtime error: load of misaligned address [[PTR:0x[0-9a-f]*]] for type 'int', which requires 4 byte alignment
+    // CHECK-LOAD-NEXT: [[PTR]]: note: pointer points here
+    // CHECK-LOAD-NEXT: {{^ 00 00 00 01 02 03 04  05}}
+    // CHECK-LOAD-NEXT: {{^             \^}}
+    return *p && 0;
+
   case 's':
-    // CHECK-STORE: misaligned.cpp:[[@LINE+1]]:5: runtime error: store to misaligned address 0x{{[0-9a-f]*}} for type 'int', which requires 4 byte alignment
+    // CHECK-STORE: misaligned.cpp:[[@LINE+4]]:5: runtime error: store to misaligned address [[PTR:0x[0-9a-f]*]] for type 'int', which requires 4 byte alignment
+    // CHECK-STORE-NEXT: [[PTR]]: note: pointer points here
+    // CHECK-STORE-NEXT: {{^ 00 00 00 01 02 03 04  05}}
+    // CHECK-STORE-NEXT: {{^             \^}}
     *p = 1;
     break;
+
   case 'r':
-    // CHECK-REFERENCE: misaligned.cpp:[[@LINE+1]]:15: runtime error: reference binding to misaligned address 0x{{[0-9a-f]*}} for type 'int', which requires 4 byte alignment
+    // CHECK-REFERENCE: misaligned.cpp:[[@LINE+4]]:15: runtime error: reference binding to misaligned address [[PTR:0x[0-9a-f]*]] for type 'int', which requires 4 byte alignment
+    // CHECK-REFERENCE-NEXT: [[PTR]]: note: pointer points here
+    // CHECK-REFERENCE-NEXT: {{^ 00 00 00 01 02 03 04  05}}
+    // CHECK-REFERENCE-NEXT: {{^             \^}}
     {int &r = *p;}
     break;
+
   case 'm':
-    // CHECK-MEMBER: misaligned.cpp:[[@LINE+1]]:15: runtime error: member access within misaligned address 0x{{[0-9a-f]*}} for type 'S', which requires 4 byte alignment
-    return s->k;
+    // CHECK-MEMBER: misaligned.cpp:[[@LINE+4]]:15: runtime error: member access within misaligned address [[PTR:0x[0-9a-f]*]] for type 'S', which requires 4 byte alignment
+    // CHECK-MEMBER-NEXT: [[PTR]]: note: pointer points here
+    // CHECK-MEMBER-NEXT: {{^ 00 00 00 01 02 03 04  05}}
+    // CHECK-MEMBER-NEXT: {{^             \^}}
+    return s->k && 0;
+
   case 'f':
-    // CHECK-MEMFUN: misaligned.cpp:[[@LINE+1]]:12: runtime error: member call on misaligned address 0x{{[0-9a-f]*}} for type 'S', which requires 4 byte alignment
-    return s->f();
+    // CHECK-MEMFUN: misaligned.cpp:[[@LINE+4]]:12: runtime error: member call on misaligned address [[PTR:0x[0-9a-f]*]] for type 'S', which requires 4 byte alignment
+    // CHECK-MEMFUN-NEXT: [[PTR]]: note: pointer points here
+    // CHECK-MEMFUN-NEXT: {{^ 00 00 00 01 02 03 04  05}}
+    // CHECK-MEMFUN-NEXT: {{^             \^}}
+    return s->f() && 0;
+
   case 'n':
     // FIXME: Provide a better source location here.
-    // CHECK-NEW: misaligned{{.*}}:0x{{[0-9a-f]*}}: runtime error: constructor call on misaligned address 0x{{[0-9a-f]*}} for type 'S', which requires 4 byte alignment
-    return (new (s) S)->k;
+    // CHECK-NEW: misaligned{{.*}}:0x{{[0-9a-f]*}}: runtime error: constructor call on misaligned address [[PTR:0x[0-9a-f]*]] for type 'S', which requires 4 byte alignment
+    // CHECK-NEW-NEXT: [[PTR]]: note: pointer points here
+    // CHECK-NEW-NEXT: {{^ 00 00 00 01 02 03 04  05}}
+    // CHECK-NEW-NEXT: {{^             \^}}
+    return (new (s) S)->k && 0;
   }
 }

Modified: compiler-rt/trunk/lib/ubsan/lit_tests/TypeCheck/vptr.cpp
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/ubsan/lit_tests/TypeCheck/vptr.cpp?rev=170415&r1=170414&r2=170415&view=diff
==============================================================================
--- compiler-rt/trunk/lib/ubsan/lit_tests/TypeCheck/vptr.cpp (original)
+++ compiler-rt/trunk/lib/ubsan/lit_tests/TypeCheck/vptr.cpp Tue Dec 18 00:30:32 2012
@@ -1,11 +1,13 @@
 // RUN: %clang -ccc-cxx -fsanitize=vptr %s -O3 -o %t
 // RUN: %t rT && %t mT && %t fT
 // RUN: %t rU && %t mU && %t fU
-// RUN: %t rS && %t rV
-// RUN: %t mS 2>&1 | FileCheck %s --check-prefix=CHECK-MEMBER
-// RUN: %t fS 2>&1 | FileCheck %s --check-prefix=CHECK-MEMFUN
-// RUN: %t mV 2>&1 | FileCheck %s --check-prefix=CHECK-MEMBER
-// RUN: %t fV 2>&1 | FileCheck %s --check-prefix=CHECK-MEMFUN
+// RUN: %t rS && %t rV && %t oV
+// RUN: %t mS 2>&1 | FileCheck %s --check-prefix=CHECK-MEMBER --strict-whitespace
+// RUN: %t fS 2>&1 | FileCheck %s --check-prefix=CHECK-MEMFUN --strict-whitespace
+// RUN: %t mV 2>&1 | FileCheck %s --check-prefix=CHECK-MEMBER --strict-whitespace
+// RUN: %t fV 2>&1 | FileCheck %s --check-prefix=CHECK-MEMFUN --strict-whitespace
+// RUN: %t oU 2>&1 | FileCheck %s --check-prefix=CHECK-OFFSET --strict-whitespace
+// RUN: %t m0 2>&1 | FileCheck %s --check-prefix=CHECK-NULL-MEMBER --strict-whitespace
 
 // FIXME: This test produces linker errors on Darwin.
 // XFAIL: darwin
@@ -46,7 +48,11 @@
   (void)((T&)u).S::v();
 
   T *p = 0;
+  char Buffer[sizeof(U)] = {};
   switch (argv[1][1]) {
+  case '0':
+    p = reinterpret_cast<T*>(Buffer);
+    break;
   case 'S':
     p = reinterpret_cast<T*>(new S);
     break;
@@ -66,11 +72,35 @@
     // Binding a reference to storage of appropriate size and alignment is OK.
     {T &r = *p;}
     break;
+
   case 'm':
-    // CHECK-MEMBER: vptr.cpp:[[@LINE+1]]:15: runtime error: member access within address 0x{{[0-9a-f]*}} which does not point to an object of type 'T'
+    // 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'
+    // CHECK-MEMBER-NEXT: [[PTR]]: note: object is of type [[DYN_TYPE:1S|1U]]
+    // CHECK-MEMBER-NEXT: {{^ .. .. .. ..  .. .. .. .. .. .. .. ..  }}
+    // CHECK-MEMBER-NEXT: {{^              \^~~~~~~~~~~(~~~~~~~~~~~~)? *$}}
+    // CHECK-MEMBER-NEXT: {{^              vptr for}} [[DYN_TYPE]]
     return p->b;
+
+    // CHECK-NULL-MEMBER: vptr.cpp:[[@LINE-2]]:15: runtime error: member access within address [[PTR:0x[0-9a-f]*]] which does not point to an object of type 'T'
+    // CHECK-NULL-MEMBER-NEXT: [[PTR]]: note: object has invalid vptr
+    // CHECK-NULL-MEMBER-NEXT: {{^ .. .. .. ..  00 00 00 00 00 00 00 00  }}
+    // CHECK-NULL-MEMBER-NEXT: {{^              \^~~~~~~~~~~(~~~~~~~~~~~~)? *$}}
+    // CHECK-NULL-MEMBER-NEXT: {{^              invalid vptr}}
+
   case 'f':
-    // CHECK-MEMFUN: vptr.cpp:[[@LINE+1]]:12: runtime error: member call on address 0x{{[0-9a-f]*}} which does not point to an object of type 'T'
+    // 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'
+    // CHECK-MEMFUN-NEXT: [[PTR]]: note: object is of type [[DYN_TYPE:1S|1U]]
+    // CHECK-MEMFUN-NEXT: {{^ .. .. .. ..  .. .. .. .. .. .. .. ..  }}
+    // CHECK-MEMFUN-NEXT: {{^              \^~~~~~~~~~~(~~~~~~~~~~~~)? *$}}
+    // CHECK-MEMFUN-NEXT: {{^              vptr for}} [[DYN_TYPE]]
     return p->g();
+
+  case 'o':
+    // 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'
+    // CHECK-OFFSET-NEXT: 0x{{[0-9a-f]*}}: note: object is base class subobject at offset {{8|16}} within object of type [[DYN_TYPE:1U]]
+    // CHECK-OFFSET-NEXT: {{^ .. .. .. ..  .. .. .. .. .. .. .. ..  .. .. .. .. .. .. .. ..  .. .. .. .. .. .. .. ..  }}
+    // CHECK-OFFSET-NEXT: {{^              \^                        (                         ~~~~~~~~~~~~)~~~~~~~~~~~ *$}}
+    // CHECK-OFFSET-NEXT: {{^                                       (                         )?vptr for}} [[DYN_TYPE]]
+    return reinterpret_cast<U*>(p)->v() - 2;
   }
 }

Modified: compiler-rt/trunk/lib/ubsan/ubsan_diag.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/ubsan/ubsan_diag.cc?rev=170415&r1=170414&r2=170415&view=diff
==============================================================================
--- compiler-rt/trunk/lib/ubsan/ubsan_diag.cc (original)
+++ compiler-rt/trunk/lib/ubsan/ubsan_diag.cc Tue Dec 18 00:30:32 2012
@@ -89,22 +89,11 @@
     break;
   case Location::LK_Null:
     RawWrite("<unknown>:");
+    break;
   }
 }
 
-Diag::~Diag() {
-  bool UseAnsiColor = PrintsToTty();
-  if (UseAnsiColor)
-    RawWrite("\033[1m");
-
-  renderLocation(Loc);
-
-  if (UseAnsiColor)
-    RawWrite("\033[31m");
-
-  RawWrite(" runtime error: ");
-  if (UseAnsiColor)
-    RawWrite("\033[0;1m");
+static void renderText(const char *Message, const Diag::Arg *Args) {
   for (const char *Msg = Message; *Msg; ++Msg) {
     if (*Msg != '%') {
       char Buffer[64];
@@ -115,25 +104,25 @@
       RawWrite(Buffer);
       Msg += I - 1;
     } else {
-      const Arg &A = Args[*++Msg - '0'];
+      const Diag::Arg &A = Args[*++Msg - '0'];
       switch (A.Kind) {
-      case AK_String:
+      case Diag::AK_String:
         Printf("%s", A.String);
         break;
-      case AK_SInt:
+      case Diag::AK_SInt:
         // 'long long' is guaranteed to be at least 64 bits wide.
         if (A.SInt >= INT64_MIN && A.SInt <= INT64_MAX)
           Printf("%lld", (long long)A.SInt);
         else
           PrintHex(A.SInt);
         break;
-      case AK_UInt:
+      case Diag::AK_UInt:
         if (A.UInt <= UINT64_MAX)
           Printf("%llu", (unsigned long long)A.UInt);
         else
           PrintHex(A.UInt);
         break;
-      case AK_Float: {
+      case Diag::AK_Float: {
         // FIXME: Support floating-point formatting in sanitizer_common's
         //        printf, and stop using snprintf here.
         char Buffer[32];
@@ -141,13 +130,138 @@
         Printf("%s", Buffer);
         break;
       }
-      case AK_Pointer:
+      case Diag::AK_Pointer:
         Printf("0x%zx", (uptr)A.Pointer);
         break;
       }
     }
   }
+}
+
+/// Find the earliest-starting range in Ranges which ends after Loc.
+static Range *upperBound(MemoryLocation Loc, Range *Ranges,
+                         unsigned NumRanges) {
+  Range *Best = 0;
+  for (unsigned I = 0; I != NumRanges; ++I)
+    if (Ranges[I].getEnd().getMemoryLocation() > Loc &&
+        (!Best ||
+         Best->getStart().getMemoryLocation() >
+         Ranges[I].getStart().getMemoryLocation()))
+      Best = &Ranges[I];
+  return Best;
+}
+
+/// Render a snippet of the address space near a location.
+static void renderMemorySnippet(MemoryLocation Loc,
+                                Range *Ranges, unsigned NumRanges,
+                                const Diag::Arg *Args) {
+  const unsigned BytesToShow = 32;
+  const unsigned MinBytesNearLoc = 4;
+
+  // Show at least the 8 bytes surrounding Loc.
+  MemoryLocation Min = Loc - MinBytesNearLoc, Max = Loc + MinBytesNearLoc;
+  for (unsigned I = 0; I < NumRanges; ++I) {
+    Min = __sanitizer::Min(Ranges[I].getStart().getMemoryLocation(), Min);
+    Max = __sanitizer::Max(Ranges[I].getEnd().getMemoryLocation(), Max);
+  }
+
+  // If we have too many interesting bytes, prefer to show bytes after Loc.
+  if (Max - Min > BytesToShow)
+    Min = __sanitizer::Min(Max - BytesToShow, Loc - MinBytesNearLoc);
+  Max = Min + BytesToShow;
+
+  // Emit data.
+  for (uptr P = Min; P != Max; ++P) {
+    // FIXME: Check that the address is readable before printing it.
+    unsigned char C = *reinterpret_cast<const unsigned char*>(P);
+    Printf("%s%02x", (P % 8 == 0) ? "  " : " ", C);
+  }
+  RawWrite("\n");
+
+  // Emit highlights.
+  Range *InRange = upperBound(Min, Ranges, NumRanges);
+  for (uptr P = Min; P != Max; ++P) {
+    char Pad = ' ', Byte = ' ';
+    if (InRange && InRange->getEnd().getMemoryLocation() == P)
+      InRange = upperBound(P, Ranges, NumRanges);
+    if (!InRange && P > Loc)
+      break;
+    if (InRange && InRange->getStart().getMemoryLocation() < P)
+      Pad = '~';
+    if (InRange && InRange->getStart().getMemoryLocation() <= P)
+      Byte = '~';
+    char Buffer[] = { Pad, Pad, P == Loc ? '^' : Byte, Byte, 0 };
+    RawWrite((P % 8 == 0) ? Buffer : &Buffer[1]);
+  }
   RawWrite("\n");
+
+  // Go over the line again, and print names for the ranges.
+  InRange = 0;
+  unsigned Spaces = 0;
+  for (uptr P = Min; P != Max; ++P) {
+    if (!InRange || InRange->getEnd().getMemoryLocation() == P)
+      InRange = upperBound(P, Ranges, NumRanges);
+    if (!InRange)
+      break;
+
+    Spaces += (P % 8) == 0 ? 2 : 1;
+
+    if (InRange && InRange->getStart().getMemoryLocation() == P) {
+      while (Spaces--)
+        RawWrite(" ");
+      renderText(InRange->getText(), Args);
+      RawWrite("\n");
+      // FIXME: We only support naming one range for now!
+      break;
+    }
+
+    Spaces += 2;
+  }
+
+  // FIXME: Print names for anything we can identify within the line:
+  //
+  //  * If we can identify the memory itself as belonging to a particular
+  //    global, stack variable, or dynamic allocation, then do so.
+  //
+  //  * If we have a pointer-size, pointer-aligned range highlighted,
+  //    determine whether the value of that range is a pointer to an
+  //    entity which we can name, and if so, print that name.
+  //
+  // This needs an external symbolizer, or (preferably) ASan instrumentation.
+}
+
+Diag::~Diag() {
+  bool UseAnsiColor = PrintsToTty();
+  if (UseAnsiColor)
+    RawWrite("\033[1m");
+
+  renderLocation(Loc);
+
+  switch (Level) {
+  case DL_Error:
+    if (UseAnsiColor)
+      RawWrite("\033[31m");
+    RawWrite(" runtime error: ");
+    if (UseAnsiColor)
+      RawWrite("\033[0;1m");
+    break;
+
+  case DL_Note:
+    if (UseAnsiColor)
+      RawWrite("\033[30m");
+    RawWrite(" note: ");
+    if (UseAnsiColor)
+      RawWrite("\033[0m");
+    break;
+  }
+
+  renderText(Message, Args);
+
   if (UseAnsiColor)
-    Printf("\033[0m");
+    RawWrite("\033[0m");
+
+  RawWrite("\n");
+
+  if (Loc.isMemoryLocation())
+    renderMemorySnippet(Loc.getMemoryLocation(), Ranges, NumRanges, Args);
 }

Modified: compiler-rt/trunk/lib/ubsan/ubsan_diag.h
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/ubsan/ubsan_diag.h?rev=170415&r1=170414&r2=170415&view=diff
==============================================================================
--- compiler-rt/trunk/lib/ubsan/ubsan_diag.h (original)
+++ compiler-rt/trunk/lib/ubsan/ubsan_diag.h Tue Dec 18 00:30:32 2012
@@ -80,6 +80,26 @@
 /// an invalid location or a module location for the caller.
 Location getCallerLocation(uptr CallerLoc = GET_CALLER_PC());
 
+/// A diagnostic severity level.
+enum DiagLevel {
+  DL_Error, ///< An error.
+  DL_Note   ///< A note, attached to a prior diagnostic.
+};
+
+/// \brief Annotation for a range of locations in a diagnostic.
+class Range {
+  Location Start, End;
+  const char *Text;
+
+public:
+  Range() : Start(), End(), Text() {}
+  Range(MemoryLocation Start, MemoryLocation End, const char *Text)
+    : Start(Start), End(End), Text(Text) {}
+  Location getStart() const { return Start; }
+  Location getEnd() const { return End; }
+  const char *getText() const { return Text; }
+};
+
 /// \brief Representation of an in-flight diagnostic.
 ///
 /// Temporary \c Diag instances are created by the handler routines to
@@ -89,10 +109,14 @@
   /// The location at which the problem occurred.
   Location Loc;
 
+  /// The diagnostic level.
+  DiagLevel Level;
+
   /// The message which will be emitted, with %0, %1, ... placeholders for
   /// arguments.
   const char *Message;
 
+public:
   /// Kinds of arguments, corresponding to members of \c Arg's union.
   enum ArgKind {
     AK_String, ///< A string argument, displayed as-is.
@@ -121,25 +145,37 @@
     };
   };
 
+private:
   static const unsigned MaxArgs = 5;
+  static const unsigned MaxRanges = 1;
 
   /// The arguments which have been added to this diagnostic so far.
   Arg Args[MaxArgs];
   unsigned NumArgs;
 
+  /// The ranges which have been added to this diagnostic so far.
+  Range Ranges[MaxRanges];
+  unsigned NumRanges;
+
   Diag &AddArg(Arg A) {
     CHECK(NumArgs != MaxArgs);
     Args[NumArgs++] = A;
     return *this;
   }
 
+  Diag &AddRange(Range A) {
+    CHECK(NumRanges != MaxRanges);
+    Ranges[NumRanges++] = A;
+    return *this;
+  }
+
   /// \c Diag objects are not copyable.
   Diag(const Diag &); // NOT IMPLEMENTED
   Diag &operator=(const Diag &);
 
 public:
-  Diag(Location Loc, const char *Message)
-    : Loc(Loc), Message(Message), NumArgs(0) {}
+  Diag(Location Loc, DiagLevel Level, const char *Message)
+    : Loc(Loc), Level(Level), Message(Message), NumArgs(0), NumRanges(0) {}
   ~Diag();
 
   Diag &operator<<(const char *Str) { return AddArg(Str); }
@@ -147,6 +183,7 @@
   Diag &operator<<(const void *V) { return AddArg(V); }
   Diag &operator<<(const TypeDescriptor &V);
   Diag &operator<<(const Value &V);
+  Diag &operator<<(const Range &R) { return AddRange(R); }
 };
 
 } // namespace __ubsan

Modified: compiler-rt/trunk/lib/ubsan/ubsan_handlers.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/ubsan/ubsan_handlers.cc?rev=170415&r1=170414&r2=170415&view=diff
==============================================================================
--- compiler-rt/trunk/lib/ubsan/ubsan_handlers.cc (original)
+++ compiler-rt/trunk/lib/ubsan/ubsan_handlers.cc Tue Dec 18 00:30:32 2012
@@ -33,17 +33,19 @@
     Loc = FallbackLoc;
 
   if (!Pointer)
-    Diag(Loc, "%0 null pointer of type %1")
+    Diag(Loc, DL_Error, "%0 null pointer of type %1")
       << TypeCheckKinds[Data->TypeCheckKind] << Data->Type;
   else if (Data->Alignment && (Pointer & (Data->Alignment - 1)))
-    Diag(Loc, "%0 misaligned address %1 for type %3, "
-              "which requires %2 byte alignment")
+    Diag(Loc, DL_Error, "%0 misaligned address %1 for type %3, "
+                        "which requires %2 byte alignment")
       << TypeCheckKinds[Data->TypeCheckKind] << (void*)Pointer
       << Data->Alignment << Data->Type;
   else
-    Diag(Loc, "%0 address %1 with insufficient space "
-              "for an object of type %2")
+    Diag(Loc, DL_Error, "%0 address %1 with insufficient space "
+                        "for an object of type %2")
       << TypeCheckKinds[Data->TypeCheckKind] << (void*)Pointer << Data->Type;
+  if (Pointer)
+    Diag(Pointer, DL_Note, "pointer points here");
 }
 void __ubsan::__ubsan_handle_type_mismatch(TypeMismatchData *Data,
                                            ValueHandle Pointer) {
@@ -57,11 +59,11 @@
 
 /// \brief Common diagnostic emission for various forms of integer overflow.
 template<typename T> static void HandleIntegerOverflow(OverflowData *Data,
-                                                      ValueHandle LHS,
-                                                      const char *Operator,
-                                                      T RHS) {
-  Diag(Data->Loc, "%0 integer overflow: "
-                  "%1 %2 %3 cannot be represented in type %4")
+                                                       ValueHandle LHS,
+                                                       const char *Operator,
+                                                       T RHS) {
+  Diag(Data->Loc, DL_Error, "%0 integer overflow: "
+                            "%1 %2 %3 cannot be represented in type %4")
     << (Data->Type.isSignedIntegerTy() ? "signed" : "unsigned")
     << Value(Data->Type, LHS) << Operator << RHS << Data->Type;
 }
@@ -101,8 +103,9 @@
 
 void __ubsan::__ubsan_handle_negate_overflow(OverflowData *Data,
                                              ValueHandle OldVal) {
-  Diag(Data->Loc, "negation of %0 cannot be represented in type %1; "
-                  "cast to an unsigned type to negate this value to itself")
+  Diag(Data->Loc, DL_Error,
+       "negation of %0 cannot be represented in type %1; "
+       "cast to an unsigned type to negate this value to itself")
     << Value(Data->Type, OldVal) << Data->Type;
 }
 void __ubsan::__ubsan_handle_negate_overflow_abort(OverflowData *Data,
@@ -116,10 +119,11 @@
   Value LHSVal(Data->Type, LHS);
   Value RHSVal(Data->Type, RHS);
   if (RHSVal.isMinusOne())
-    Diag(Data->Loc, "division of %0 by -1 cannot be represented in type %1")
+    Diag(Data->Loc, DL_Error,
+         "division of %0 by -1 cannot be represented in type %1")
       << LHSVal << Data->Type;
   else
-    Diag(Data->Loc, "division by zero");
+    Diag(Data->Loc, DL_Error, "division by zero");
 }
 void __ubsan::__ubsan_handle_divrem_overflow_abort(OverflowData *Data,
                                                     ValueHandle LHS,
@@ -134,15 +138,17 @@
   Value LHSVal(Data->LHSType, LHS);
   Value RHSVal(Data->RHSType, RHS);
   if (RHSVal.isNegative())
-    Diag(Data->Loc, "shift exponent %0 is negative") << RHSVal;
+    Diag(Data->Loc, DL_Error, "shift exponent %0 is negative") << RHSVal;
   else if (RHSVal.getPositiveIntValue() >= Data->LHSType.getIntegerBitWidth())
-    Diag(Data->Loc, "shift exponent %0 is too large for %1-bit type %2")
+    Diag(Data->Loc, DL_Error,
+         "shift exponent %0 is too large for %1-bit type %2")
       << RHSVal << Data->LHSType.getIntegerBitWidth() << Data->LHSType;
   else if (LHSVal.isNegative())
-    Diag(Data->Loc, "left shift of negative value %0") << LHSVal;
+    Diag(Data->Loc, DL_Error, "left shift of negative value %0") << LHSVal;
   else
-    Diag(Data->Loc, "left shift of %0 by %1 places cannot be represented "
-                    "in type %2") << LHSVal << RHSVal << Data->LHSType;
+    Diag(Data->Loc, DL_Error,
+         "left shift of %0 by %1 places cannot be represented in type %2")
+      << LHSVal << RHSVal << Data->LHSType;
 }
 void __ubsan::__ubsan_handle_shift_out_of_bounds_abort(
                                                      ShiftOutOfBoundsData *Data,
@@ -153,20 +159,21 @@
 }
 
 void __ubsan::__ubsan_handle_builtin_unreachable(UnreachableData *Data) {
-  Diag(Data->Loc, "execution reached a __builtin_unreachable() call");
+  Diag(Data->Loc, DL_Error, "execution reached a __builtin_unreachable() call");
   Die();
 }
 
 void __ubsan::__ubsan_handle_missing_return(UnreachableData *Data) {
-  Diag(Data->Loc, "execution reached the end of a value-returning function "
-                  "without returning a value");
+  Diag(Data->Loc, DL_Error,
+       "execution reached the end of a value-returning function "
+       "without returning a value");
   Die();
 }
 
 void __ubsan::__ubsan_handle_vla_bound_not_positive(VLABoundData *Data,
                                                     ValueHandle Bound) {
-  Diag(Data->Loc, "variable length array bound evaluates to "
-                  "non-positive value %0")
+  Diag(Data->Loc, DL_Error, "variable length array bound evaluates to "
+                            "non-positive value %0")
     << Value(Data->Type, Bound);
 }
 void __ubsan::__ubsan_handle_vla_bound_not_positive_abort(VLABoundData *Data,
@@ -178,29 +185,29 @@
 
 void __ubsan::__ubsan_handle_float_cast_overflow(FloatCastOverflowData *Data,
                                                  ValueHandle From) {
-  Diag(getCallerLocation(), "value %0 is outside the range of representable "
-                            "values of type %2")
+  Diag(getCallerLocation(), DL_Error,
+       "value %0 is outside the range of representable values of type %2")
     << Value(Data->FromType, From) << Data->FromType << Data->ToType;
 }
 void __ubsan::__ubsan_handle_float_cast_overflow_abort(
                                                     FloatCastOverflowData *Data,
                                                     ValueHandle From) {
-  Diag(getCallerLocation(), "value %0 is outside the range of representable "
-                            "values of type %2")
+  Diag(getCallerLocation(), DL_Error,
+       "value %0 is outside the range of representable values of type %2")
     << Value(Data->FromType, From) << Data->FromType << Data->ToType;
   Die();
 }
 
 void __ubsan::__ubsan_handle_load_invalid_value(InvalidValueData *Data,
                                                 ValueHandle Val) {
-  Diag(getCallerLocation(), "load of value %0, which is not a valid value for "
-                            "type %1")
+  Diag(getCallerLocation(), DL_Error,
+       "load of value %0, which is not a valid value for type %1")
     << Value(Data->Type, Val) << Data->Type;
 }
 void __ubsan::__ubsan_handle_load_invalid_value_abort(InvalidValueData *Data,
                                                       ValueHandle Val) {
-  Diag(getCallerLocation(), "load of value %0, which is not a valid value for "
-                            "type %1")
+  Diag(getCallerLocation(), DL_Error,
+       "load of value %0, which is not a valid value for type %1")
     << Value(Data->Type, Val) << Data->Type;
   Die();
 }

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=170415&r1=170414&r2=170415&view=diff
==============================================================================
--- compiler-rt/trunk/lib/ubsan/ubsan_handlers_cxx.cc (original)
+++ compiler-rt/trunk/lib/ubsan/ubsan_handlers_cxx.cc Tue Dec 18 00:30:32 2012
@@ -27,34 +27,42 @@
 }
 
 static void HandleDynamicTypeCacheMiss(
-  DynamicTypeCacheMissData *Data, ValueHandle Pointer, ValueHandle Hash,
-  bool abort) {
+    DynamicTypeCacheMissData *Data, ValueHandle Pointer, ValueHandle Hash,
+    bool Abort) {
   if (checkDynamicType((void*)Pointer, Data->TypeInfo, Hash))
     // Just a cache miss. The type matches after all.
     return;
 
-  Diag(Data->Loc, "%0 address %1 which does not point to an object of type %2")
+  Diag(Data->Loc, DL_Error,
+       "%0 address %1 which does not point to an object of type %2")
     << TypeCheckKinds[Data->TypeCheckKind] << (void*)Pointer << Data->Type;
-  // FIXME: If possible, say what type it actually points to. Produce a note
-  //        pointing out the vptr:
-  // lib/VMCore/Instructions.cpp:2020:10: runtime error: member call on address
-  //       0xb7a4440 which does not point to an object of type
-  //       'llvm::OverflowingBinaryOperator'
-  //   return cast<OverflowingBinaryOperator>(this)->hasNoSignedWrap();
-  //                                               ^
-  // 0xb7a4440: note: object is of type 'llvm::BinaryOperator'
-  //   00 00 00 00  e0 f7 c5 09 00 00 00 00  20 00 00 00
-  //                ^~~~~~~~~~~
-  //                vptr for 'llvm::BinaryOperator'
-  if (abort)
+
+  // If possible, say what type it actually points to.
+  // FIXME: Demangle the type names.
+  DynamicTypeInfo DTI = getDynamicTypeInfo((void*)Pointer);
+  if (!DTI.isValid())
+    Diag(Pointer, DL_Note, "object has invalid vptr")
+      << DTI.getMostDerivedTypeName()
+      << Range(Pointer, Pointer + sizeof(uptr), "invalid vptr");
+  else if (!DTI.getOffset())
+    Diag(Pointer, DL_Note, "object is of type %0")
+      << DTI.getMostDerivedTypeName()
+      << Range(Pointer, Pointer + sizeof(uptr), "vptr for %0");
+  else
+    Diag(Pointer - DTI.getOffset(), DL_Note,
+         "object is base class subobject at offset %0 within object of type %1")
+      << DTI.getOffset() << DTI.getMostDerivedTypeName()
+      << Range(Pointer, Pointer + sizeof(uptr), "vptr for %1");
+
+  if (Abort)
     Die();
 }
 
 void __ubsan::__ubsan_handle_dynamic_type_cache_miss(
-  DynamicTypeCacheMissData *Data, ValueHandle Pointer, ValueHandle Hash) {
+    DynamicTypeCacheMissData *Data, ValueHandle Pointer, ValueHandle Hash) {
   HandleDynamicTypeCacheMiss(Data, Pointer, Hash, false);
 }
 void __ubsan::__ubsan_handle_dynamic_type_cache_miss_abort(
-  DynamicTypeCacheMissData *Data, ValueHandle Pointer, ValueHandle Hash) {
+    DynamicTypeCacheMissData *Data, ValueHandle Pointer, ValueHandle Hash) {
   HandleDynamicTypeCacheMiss(Data, Pointer, Hash, true);
 }

Modified: compiler-rt/trunk/lib/ubsan/ubsan_type_hash.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/ubsan/ubsan_type_hash.cc?rev=170415&r1=170414&r2=170415&view=diff
==============================================================================
--- compiler-rt/trunk/lib/ubsan/ubsan_type_hash.cc (original)
+++ compiler-rt/trunk/lib/ubsan/ubsan_type_hash.cc Tue Dec 18 00:30:32 2012
@@ -25,7 +25,7 @@
   class type_info {
   public:
     virtual ~type_info();
-  private:
+
     const char *__type_name;
   };
 }
@@ -160,8 +160,14 @@
   std::type_info *TypeInfo;
 };
 VtablePrefix *getVtablePrefix(void *Object) {
-  VtablePrefix **Ptr = reinterpret_cast<VtablePrefix**>(Object);
-  return *Ptr - 1;
+  VtablePrefix **VptrPtr = reinterpret_cast<VtablePrefix**>(Object);
+  if (!*VptrPtr)
+    return 0;
+  VtablePrefix *Prefix = *VptrPtr - 1;
+  if (Prefix->Offset > 0 || !Prefix->TypeInfo)
+    // This can't possibly be a valid vtable.
+    return 0;
+  return Prefix;
 }
 
 }
@@ -178,8 +184,7 @@
   }
 
   VtablePrefix *Vtable = getVtablePrefix(Object);
-  if (Vtable + 1 == 0 || Vtable->Offset > 0)
-    // This can't possibly be a valid vtable.
+  if (!Vtable)
     return false;
 
   // Check that this is actually a type_info object for a class type.
@@ -197,3 +202,10 @@
   *Bucket = Hash;
   return true;
 }
+
+__ubsan::DynamicTypeInfo __ubsan::getDynamicTypeInfo(void *Object) {
+  VtablePrefix *Vtable = getVtablePrefix(Object);
+  if (!Vtable)
+    return DynamicTypeInfo(0, 0);
+  return DynamicTypeInfo(Vtable->TypeInfo->__type_name, -Vtable->Offset);
+}

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=170415&r1=170414&r2=170415&view=diff
==============================================================================
--- compiler-rt/trunk/lib/ubsan/ubsan_type_hash.h (original)
+++ compiler-rt/trunk/lib/ubsan/ubsan_type_hash.h Tue Dec 18 00:30:32 2012
@@ -19,6 +19,27 @@
 
 typedef uptr HashValue;
 
+/// \brief Information about the dynamic type of an object (extracted from its
+/// vptr).
+class DynamicTypeInfo {
+  const char *MostDerivedTypeName;
+  sptr Offset;
+
+public:
+  DynamicTypeInfo(const char *MDTN, sptr Offset)
+    : MostDerivedTypeName(MDTN), Offset(Offset) {}
+
+  /// Determine whether the object had a valid dynamic type.
+  bool isValid() const { return MostDerivedTypeName; }
+  /// Get the name of the most-derived type of the object.
+  const char *getMostDerivedTypeName() const { return MostDerivedTypeName; }
+  /// Get the offset from the most-derived type to this base class.
+  sptr getOffset() const { return Offset; }
+};
+
+/// \brief Get information about the dynamic type of an object.
+DynamicTypeInfo getDynamicTypeInfo(void *Object);
+
 /// \brief Check whether the dynamic type of \p Object has a \p Type subobject
 /// at offset 0.
 /// \return \c true if the type matches, \c false if not.





More information about the llvm-commits mailing list