diff --git a/exp-ptrcheck/h_main.c b/exp-ptrcheck/h_main.c
index e5b0284b6..1cc27ea75 100644
--- a/exp-ptrcheck/h_main.c
+++ b/exp-ptrcheck/h_main.c
@@ -1023,7 +1023,8 @@ void set_mem ( Addr a, SizeT len, Seg* seg )
if (len > 100 * 1000 * 1000)
VG_(message)(Vg_UserMsg,
- "Warning: set address range state: large range %lu", len);
+ "Warning: set address range state: large range %lu\n",
+ len);
a = VG_ROUNDDN(a, sizeof(UWord));
end = VG_ROUNDUP(a + len, sizeof(UWord));
@@ -2061,7 +2062,7 @@ void h_post_reg_write_clientcall(ThreadId tid, PtrdiffT guest_state_offset,
else if (f == (Addr)h_replace_free
|| f == (Addr)h_replace___builtin_delete
|| f == (Addr)h_replace___builtin_vec_delete
- // || f == (Addr)VG_(cli_block_size)
+ // || f == (Addr)VG_(cli_block_size)
|| f == (Addr)VG_(message))
{
// Probably best to set the (non-existent!) return value to
@@ -5308,25 +5309,25 @@ void h_fini ( Int exitcode )
{
if (VG_(clo_verbosity) >= 2) {
VG_(message)(Vg_DebugMsg,
- " h_: %'10llu client allocs, %'10llu client frees",
+ " h_: %'10llu client allocs, %'10llu client frees\n",
stats__client_mallocs, stats__client_frees);
VG_(message)(Vg_DebugMsg,
- " h_: %'10llu Segs allocd, %'10llu Segs recycled",
+ " h_: %'10llu Segs allocd, %'10llu Segs recycled\n",
stats__segs_allocd, stats__segs_recycled);
}
#if 0
if (h_clo_lossage_check) {
- VG_(message)(Vg_UserMsg, "");
- VG_(message)(Vg_UserMsg, "%12lld total memory references",
+ VG_(message)(Vg_UserMsg, "\n");
+ VG_(message)(Vg_UserMsg, "%12lld total memory references\n",
stats__tot_mem_refs);
- VG_(message)(Vg_UserMsg, "%12lld of which are in a known segment",
+ VG_(message)(Vg_UserMsg, "%12lld of which are in a known segment\n",
stats__refs_in_a_seg);
- VG_(message)(Vg_UserMsg, "%12lld of which are 'lost' w.r.t the seg",
+ VG_(message)(Vg_UserMsg, "%12lld of which are 'lost' w.r.t the seg\n",
stats__refs_lost_seg);
- VG_(message)(Vg_UserMsg, "");
+ VG_(message)(Vg_UserMsg, "\n");
show_lossage();
- VG_(message)(Vg_UserMsg, "");
+ VG_(message)(Vg_UserMsg, "\n");
} else {
tl_assert( 0 == VG_(OSetGen_Size)(lossage) );
}
diff --git a/exp-ptrcheck/pc_common.c b/exp-ptrcheck/pc_common.c
index 90f9098c5..3d75748d3 100644
--- a/exp-ptrcheck/pc_common.c
+++ b/exp-ptrcheck/pc_common.c
@@ -38,6 +38,7 @@
#include "pub_tool_basics.h"
#include "pub_tool_libcbase.h"
#include "pub_tool_libcprint.h"
+#include "pub_tool_xarray.h"
#include "pub_tool_mallocfree.h"
#include "pub_tool_libcassert.h"
#include "pub_tool_options.h"
@@ -96,7 +97,7 @@ void pc_print_debug_usage(void)
//////////////////////////////////////////////////////////////
// //
-// Error management //
+// Error management -- storage //
// //
//////////////////////////////////////////////////////////////
@@ -133,8 +134,8 @@ typedef
Addr addr;
SSizeT sszB; /* -ve is write, +ve is read */
Seg* vseg;
- Char descr1[96];
- Char descr2[96];
+ XArray* descr1; /* XArray* of HChar */
+ XArray* descr2; /* XArray* of HChar */
Char datasym[96];
PtrdiffT datasymoff;
} Heap;
@@ -250,6 +251,47 @@ Bool pc_eq_Error ( VgRes res, Error* e1, Error* e2 )
}
+//////////////////////////////////////////////////////////////
+// //
+// Error management -- printing //
+// //
+//////////////////////////////////////////////////////////////
+
+/* This is the "this error is due to be printed shortly; so have a
+ look at it any print any preamble you want" function. Which, in
+ Ptrcheck, we don't use. Hence a no-op.
+*/
+void pc_before_pp_Error ( Error* err ) {
+}
+
+/* Do a printf-style operation on either the XML or normal output
+ channel, depending on the setting of VG_(clo_xml).
+*/
+static void emit_WRK ( HChar* format, va_list vargs )
+{
+ if (VG_(clo_xml)) {
+ VG_(vprintf_xml)(format, vargs);
+ } else {
+ VG_(vmessage)(Vg_UserMsg, format, vargs);
+ }
+}
+static void emit ( HChar* format, ... ) PRINTF_CHECK(1, 2);
+static void emit ( HChar* format, ... )
+{
+ va_list vargs;
+ va_start(vargs, format);
+ emit_WRK(format, vargs);
+ va_end(vargs);
+}
+static void emiN ( HChar* format, ... ) /* With NO FORMAT CHECK */
+{
+ va_list vargs;
+ va_start(vargs, format);
+ emit_WRK(format, vargs);
+ va_end(vargs);
+}
+
+
static Char* readwrite(SSizeT sszB)
{
return ( sszB < 0 ? "write" : "read" );
@@ -261,6 +303,8 @@ static Word Word__abs ( Word w ) {
void pc_pp_Error ( Error* err )
{
+ const Bool xml = VG_(clo_xml); /* a shorthand, that's all */
+
XError *xe = (XError*)VG_(get_error_extra)(err);
tl_assert(xe);
@@ -268,15 +312,34 @@ void pc_pp_Error ( Error* err )
//----------------------------------------------------------
case XE_SorG:
- tl_assert(xe);
- VG_(message)(Vg_UserMsg, "Invalid %s of size %ld",
- xe->XE.SorG.sszB < 0 ? "write" : "read",
- Word__abs(xe->XE.SorG.sszB) );
- VG_(pp_ExeContext)( VG_(get_error_where)(err) );
- VG_(message)(Vg_UserMsg, " Address %#lx expected vs actual:",
- xe->XE.SorG.addr);
- VG_(message)(Vg_UserMsg, " Expected: %s", &xe->XE.SorG.expect[0] );
- VG_(message)(Vg_UserMsg, " Actual: %s", &xe->XE.SorG.actual[0] );
+
+ if (xml) {
+
+ emit( " SorG\n");
+ emit( " Invalid %s of size %ld\n",
+ xe->XE.SorG.sszB < 0 ? "write" : "read",
+ Word__abs(xe->XE.SorG.sszB) );
+ VG_(pp_ExeContext)( VG_(get_error_where)(err) );
+
+ emit( " Address %#lx expected vs actual:\n",
+ xe->XE.SorG.addr );
+ emiN( " Expected: %t\n",
+ &xe->XE.SorG.expect[0] );
+ emiN( " Actual: %t\n",
+ &xe->XE.SorG.actual[0] );
+
+ } else {
+
+ emit( "Invalid %s of size %ld\n",
+ xe->XE.SorG.sszB < 0 ? "write" : "read",
+ Word__abs(xe->XE.SorG.sszB) );
+ VG_(pp_ExeContext)( VG_(get_error_where)(err) );
+
+ emit( " Address %#lx expected vs actual:\n", xe->XE.SorG.addr );
+ emit( " Expected: %s\n", &xe->XE.SorG.expect[0] );
+ emit( " Actual: %s\n", &xe->XE.SorG.actual[0] );
+
+ }
break;
//----------------------------------------------------------
@@ -289,12 +352,29 @@ void pc_pp_Error ( Error* err )
if (NONPTR == vseg) {
// Access via a non-pointer
- VG_(message)(Vg_UserMsg, "Invalid %s of size %ld",
- readwrite(xe->XE.Heap.sszB),
- Word__abs(xe->XE.Heap.sszB));
- VG_(pp_ExeContext)( VG_(get_error_where)(err) );
- VG_(message)(Vg_UserMsg,
- " Address %#lx is not derived from any known block", a);
+
+ if (xml) {
+
+ emit( " Heap\n");
+ emit( " Invalid %s of size %ld\n",
+ readwrite(xe->XE.Heap.sszB),
+ Word__abs(xe->XE.Heap.sszB) );
+ VG_(pp_ExeContext)( VG_(get_error_where)(err) );
+
+ emit( " Address %#lx is not derived from "
+ "any known block\n", a );
+
+ } else {
+
+ emit( "Invalid %s of size %ld\n",
+ readwrite(xe->XE.Heap.sszB),
+ Word__abs(xe->XE.Heap.sszB) );
+ VG_(pp_ExeContext)( VG_(get_error_where)(err) );
+
+ emit( " Address %#lx is not derived from "
+ "any known block\n", a );
+
+ }
} else {
// Access via a pointer, but outside its range.
@@ -308,30 +388,77 @@ void pc_pp_Error ( Error* err )
? "Doubly-invalid" : "Invalid" );
legit = ( Seg__is_freed(vseg) ? "once-" : "" );
- VG_(message)(Vg_UserMsg, "%s %s of size %ld", how_invalid,
- readwrite(xe->XE.Heap.sszB),
- Word__abs(xe->XE.Heap.sszB));
- VG_(pp_ExeContext)( VG_(get_error_where)(err) );
+ if (xml) {
+
+ emit( " Heap\n");
+ emit( " %s %s of size %ld\n",
+ how_invalid,
+ readwrite(xe->XE.Heap.sszB),
+ Word__abs(xe->XE.Heap.sszB) );
+ VG_(pp_ExeContext)( VG_(get_error_where)(err) );
+
+ emit( " Address %#lx is %lu bytes %s "
+ "the accessing pointer's\n",
+ a, miss_size, place );
+ emit( " %slegitimate range, "
+ "a block of size %lu %s\n",
+ legit, Seg__size(vseg),
+ Seg__is_freed(vseg) ? "free'd" : "alloc'd" );
+ VG_(pp_ExeContext)(Seg__where(vseg));
+
+ } else {
+
+ emit( "%s %s of size %ld\n",
+ how_invalid,
+ readwrite(xe->XE.Heap.sszB),
+ Word__abs(xe->XE.Heap.sszB) );
+ VG_(pp_ExeContext)( VG_(get_error_where)(err) );
+
+ emit( " Address %#lx is %lu bytes %s the accessing pointer's\n",
+ a, miss_size, place );
+ emit( " %slegitimate range, a block of size %lu %s\n",
+ legit, Seg__size(vseg),
+ Seg__is_freed(vseg) ? "free'd" : "alloc'd" );
+ VG_(pp_ExeContext)(Seg__where(vseg));
+
+ }
+ }
+
+ /* If we have a better description of the address, show it.
+ Note that in XML mode, it will already by nicely wrapped up
+ in tags, either or , so we can just emit
+ it verbatim. */
+ if (xml) {
+
+ if (xe->XE.Heap.descr1)
+ emiN( " %t\n",
+ (HChar*)VG_(indexXA)( xe->XE.Heap.descr1, 0 ) );
+ if (xe->XE.Heap.descr2)
+ emiN( " %t\n",
+ (HChar*)VG_(indexXA)( xe->XE.Heap.descr2, 0 ) );
+ if (xe->XE.Heap.datasym[0] != 0)
+ emiN( " Address 0x%llx is %llu bytes "
+ "inside data symbol \"%t\"\n",
+ (ULong)xe->XE.Heap.addr,
+ (ULong)xe->XE.Heap.datasymoff,
+ xe->XE.Heap.datasym );
+
+ } else {
+
+ if (xe->XE.Heap.descr1)
+ emit( " %s\n",
+ (HChar*)VG_(indexXA)( xe->XE.Heap.descr1, 0 ) );
+ if (xe->XE.Heap.descr2)
+ emit( " %s\n",
+ (HChar*)VG_(indexXA)( xe->XE.Heap.descr2, 0 ) );
+ if (xe->XE.Heap.datasym[0] != 0)
+ emit( " Address 0x%llx is %llu bytes "
+ "inside data symbol \"%s\"\n",
+ (ULong)xe->XE.Heap.addr,
+ (ULong)xe->XE.Heap.datasymoff,
+ xe->XE.Heap.datasym );
- VG_(message)(Vg_UserMsg,
- " Address %#lx is %lu bytes %s the accessing pointer's",
- a, miss_size, place);
- VG_(message)(Vg_UserMsg,
- " %slegitimate range, a block of size %lu %s",
- legit, Seg__size(vseg),
- Seg__is_freed(vseg) ? "free'd" : "alloc'd" );
- VG_(pp_ExeContext)(Seg__where(vseg));
}
- if (xe->XE.Heap.descr1[0] != 0)
- VG_(message)(Vg_UserMsg, " %s", xe->XE.Heap.descr1);
- if (xe->XE.Heap.descr2[0] != 0)
- VG_(message)(Vg_UserMsg, " %s", xe->XE.Heap.descr2);
- if (xe->XE.Heap.datasym[0] != 0)
- VG_(message)(Vg_UserMsg, " Address 0x%llx is %llu bytes "
- "inside data symbol \"%s\"",
- (ULong)xe->XE.Heap.addr,
- (ULong)xe->XE.Heap.datasymoff,
- xe->XE.Heap.datasym);
break;
}
@@ -344,32 +471,69 @@ void pc_pp_Error ( Error* err )
tl_assert(BOTTOM != seg1);
tl_assert(BOTTOM != seg2 && UNKNOWN != seg2);
- VG_(message)(Vg_UserMsg, "Invalid arguments to %s", xe->XE.Arith.opname);
- VG_(pp_ExeContext)( VG_(get_error_where)(err) );
+ if (xml) {
- if (seg1 != seg2) {
- if (NONPTR == seg1) {
- VG_(message)(Vg_UserMsg, " First arg not a pointer");
- } else if (UNKNOWN == seg1) {
- VG_(message)(Vg_UserMsg, " First arg may be a pointer");
+ emit( " Arith\n");
+ emit( " Invalid arguments to %s\n",
+ xe->XE.Arith.opname );
+ VG_(pp_ExeContext)( VG_(get_error_where)(err) );
+
+ if (seg1 != seg2) {
+ if (NONPTR == seg1) {
+ emit( " First arg not a pointer\n" );
+ } else if (UNKNOWN == seg1) {
+ emit( " First arg may be a pointer\n" );
+ } else {
+ emit( " First arg derived from address %#lx of "
+ "%lu-byte block alloc'd\n",
+ Seg__addr(seg1), Seg__size(seg1) );
+ VG_(pp_ExeContext)(Seg__where(seg1));
+ }
+ which = "Second arg";
} else {
- VG_(message)(Vg_UserMsg, " First arg derived from address %#lx of "
- "%lu-byte block alloc'd",
- Seg__addr(seg1), Seg__size(seg1) );
- VG_(pp_ExeContext)(Seg__where(seg1));
+ which = "Both args";
}
- which = "Second arg";
+ if (NONPTR == seg2) {
+ emit( " %s not a pointer\n", which );
+ } else {
+ emit( " %s derived from address %#lx of "
+ "%lu-byte block alloc'd\n",
+ which, Seg__addr(seg2), Seg__size(seg2) );
+ VG_(pp_ExeContext)(Seg__where(seg2));
+ }
+
} else {
- which = "Both args";
- }
- if (NONPTR == seg2) {
- VG_(message)(Vg_UserMsg, " %s not a pointer", which);
- } else {
- VG_(message)(Vg_UserMsg, " %s derived from address %#lx of "
- "%lu-byte block alloc'd",
- which, Seg__addr(seg2), Seg__size(seg2) );
- VG_(pp_ExeContext)(Seg__where(seg2));
+
+ emit( "Invalid arguments to %s\n",
+ xe->XE.Arith.opname );
+ VG_(pp_ExeContext)( VG_(get_error_where)(err) );
+
+ if (seg1 != seg2) {
+ if (NONPTR == seg1) {
+ emit( " First arg not a pointer\n" );
+ } else if (UNKNOWN == seg1) {
+ emit( " First arg may be a pointer\n" );
+ } else {
+ emit( " First arg derived from address %#lx of "
+ "%lu-byte block alloc'd\n",
+ Seg__addr(seg1), Seg__size(seg1) );
+ VG_(pp_ExeContext)(Seg__where(seg1));
+ }
+ which = "Second arg";
+ } else {
+ which = "Both args";
+ }
+ if (NONPTR == seg2) {
+ emit( " %s not a pointer\n", which );
+ } else {
+ emit( " %s derived from address %#lx of "
+ "%lu-byte block alloc'd\n",
+ which, Seg__addr(seg2), Seg__size(seg2) );
+ VG_(pp_ExeContext)(Seg__where(seg2));
+ }
+
}
+
break;
}
@@ -392,40 +556,88 @@ void pc_pp_Error ( Error* err )
// freed block
tl_assert(is_known_segment(seglo));
tl_assert(Seg__is_freed(seglo)); // XXX what if it's now recycled?
- VG_(message)(Vg_UserMsg, "%s%s contains unaddressable byte(s)",
- what, s);
- VG_(pp_ExeContext)( VG_(get_error_where)(err) );
- VG_(message)(Vg_UserMsg, " Address %#lx is %ld bytes inside a "
- "%ld-byte block free'd",
- lo, lo-Seg__addr(seglo),
- Seg__size(seglo) );
- VG_(pp_ExeContext)(Seg__where(seglo));
+ if (xml) {
+
+ emit( " SysParam\n");
+ emit( " %s%s contains unaddressable byte(s)\n",
+ what, s );
+ VG_(pp_ExeContext)( VG_(get_error_where)(err) );
+
+ emit( " Address %#lx is %ld bytes inside a "
+ "%ld-byte block free'd\n",
+ lo, lo-Seg__addr(seglo), Seg__size(seglo) );
+ VG_(pp_ExeContext)(Seg__where(seglo));
+
+ } else {
+
+ emit( " %s%s contains unaddressable byte(s)\n",
+ what, s );
+ VG_(pp_ExeContext)( VG_(get_error_where)(err) );
+
+ emit( " Address %#lx is %ld bytes inside a "
+ "%ld-byte block free'd\n",
+ lo, lo-Seg__addr(seglo), Seg__size(seglo) );
+ VG_(pp_ExeContext)(Seg__where(seglo));
+
+ }
} else {
// mismatch
- VG_(message)(Vg_UserMsg, "%s%s is non-contiguous", what, s);
- VG_(pp_ExeContext)( VG_(get_error_where)(err) );
- if (UNKNOWN == seglo) {
- VG_(message)(Vg_UserMsg, " First byte is not inside a known block");
+ if (xml) {
+
+ emit( " SysParam\n");
+ emit( " %s%s is non-contiguous\n",
+ what, s );
+ VG_(pp_ExeContext)( VG_(get_error_where)(err) );
+
+ if (UNKNOWN == seglo) {
+ emit( " First byte is "
+ "not inside a known block\n" );
+ } else {
+ emit( " First byte (%#lx) is %ld bytes inside a "
+ "%ld-byte block alloc'd\n",
+ lo, lo-Seg__addr(seglo), Seg__size(seglo) );
+ VG_(pp_ExeContext)(Seg__where(seglo));
+ }
+
+ if (UNKNOWN == seghi) {
+ emit( " Last byte is "
+ "not inside a known block\n" );
+ } else {
+ emit( " Last byte (%#lx) is %ld bytes inside a "
+ "%ld-byte block alloc'd\n",
+ hi, hi-Seg__addr(seghi), Seg__size(seghi) );
+ VG_(pp_ExeContext)(Seg__where(seghi));
+ }
+
} else {
- VG_(message)(Vg_UserMsg, " First byte (%#lx) is %ld bytes inside a "
- "%ld-byte block alloc'd",
- lo, lo-Seg__addr(seglo),
- Seg__size(seglo) );
- VG_(pp_ExeContext)(Seg__where(seglo));
+
+ emit( "%s%s is non-contiguous\n",
+ what, s );
+ VG_(pp_ExeContext)( VG_(get_error_where)(err) );
+
+ if (UNKNOWN == seglo) {
+ emit( " First byte is not inside a known block\n" );
+ } else {
+ emit( " First byte (%#lx) is %ld bytes inside a "
+ "%ld-byte block alloc'd\n",
+ lo, lo-Seg__addr(seglo), Seg__size(seglo) );
+ VG_(pp_ExeContext)(Seg__where(seglo));
+ }
+
+ if (UNKNOWN == seghi) {
+ emit( " Last byte is not inside a known block\n" );
+ } else {
+ emit( " Last byte (%#lx) is %ld bytes inside a "
+ "%ld-byte block alloc'd\n",
+ hi, hi-Seg__addr(seghi), Seg__size(seghi) );
+ VG_(pp_ExeContext)(Seg__where(seghi));
+ }
+
}
- if (UNKNOWN == seghi) {
- VG_(message)(Vg_UserMsg, " Last byte is not inside a known block");
- } else {
- VG_(message)(Vg_UserMsg, " Last byte (%#lx) is %ld bytes inside a "
- "%ld-byte block alloc'd",
- hi, hi-Seg__addr(seghi),
- Seg__size(seghi) );
- VG_(pp_ExeContext)(Seg__where(seghi));
- }
}
break;
}
@@ -442,38 +654,71 @@ UInt pc_update_Error_extra ( Error* err )
tl_assert(xe);
switch (xe->tag) {
case XE_SorG:
- return sizeof(XError);
+ break;
case XE_Heap: {
- tl_assert(sizeof(xe->XE.Heap.descr1) == sizeof(xe->XE.Heap.descr2));
- tl_assert(sizeof(xe->XE.Heap.descr1) > 0);
+ Bool have_descr;
+
tl_assert(sizeof(xe->XE.Heap.datasym) > 0);
- VG_(memset)(&xe->XE.Heap.descr1, 0, sizeof(xe->XE.Heap.descr1));
- VG_(memset)(&xe->XE.Heap.descr2, 0, sizeof(xe->XE.Heap.descr2));
+ xe->XE.Heap.datasymoff = 0;
+ xe->XE.Heap.datasym[0] = 0;
+
+ tl_assert(!xe->XE.Heap.descr1);
+ tl_assert(!xe->XE.Heap.descr2);
+
+ xe->XE.Heap.descr1
+ = VG_(newXA)( VG_(malloc), "pc.update_extra.Heap.descr1",
+ VG_(free), sizeof(HChar) );
+ xe->XE.Heap.descr2
+ = VG_(newXA)( VG_(malloc), "pc.update_extra.Heap.descr1",
+ VG_(free), sizeof(HChar) );
+
VG_(memset)(&xe->XE.Heap.datasym, 0, sizeof(xe->XE.Heap.datasym));
xe->XE.Heap.datasymoff = 0;
- if (VG_(get_data_description)( &xe->XE.Heap.descr1[0],
- &xe->XE.Heap.descr2[0],
- sizeof(xe->XE.Heap.descr1)-1,
- xe->XE.Heap.addr )) {
- tl_assert(xe->XE.Heap.descr1[sizeof(xe->XE.Heap.descr1)-1] == 0);
- tl_assert(xe->XE.Heap.descr1[sizeof(xe->XE.Heap.descr2)-1] == 0);
+
+ have_descr
+ = VG_(get_data_description)( xe->XE.Heap.descr1,
+ xe->XE.Heap.descr2,
+ xe->XE.Heap.addr );
+
+ /* If there's nothing in descr1/2, free it. Why is it safe to
+ to VG_(indexXA) at zero here? Because
+ VG_(get_data_description) guarantees to zero terminate
+ descr1/2 regardless of the outcome of the call. So there's
+ always at least one element in each XA after the call.
+ */
+ if (0 == VG_(strlen)( VG_(indexXA)( xe->XE.Heap.descr1, 0 ))
+ || !have_descr) {
+ VG_(deleteXA)( xe->XE.Heap.descr1 );
+ xe->XE.Heap.descr1 = NULL;
}
- else
- if (VG_(get_datasym_and_offset)( xe->XE.Heap.addr,
- &xe->XE.Heap.datasym[0],
- sizeof(xe->XE.Heap.datasym)-1,
- &xe->XE.Heap.datasymoff )) {
- tl_assert(xe->XE.Heap.datasym[sizeof(xe->XE.Heap.datasym)-1] == 0);
+ if (0 == VG_(strlen)( VG_(indexXA)( xe->XE.Heap.descr2, 0 ))
+ || !have_descr) {
+ VG_(deleteXA)( xe->XE.Heap.descr2 );
+ xe->XE.Heap.descr2 = NULL;
}
- return sizeof(XError);
+
+ /* If Dwarf3 info produced nothing useful, see at least if
+ we can fish something useful out of the ELF symbol info. */
+ if (!have_descr) {
+ if (VG_(get_datasym_and_offset)(
+ xe->XE.Heap.addr, &xe->XE.Heap.datasym[0],
+ sizeof(xe->XE.Heap.datasym)-1,
+ &xe->XE.Heap.datasymoff )
+ ) {
+ tl_assert(xe->XE.Heap.datasym[sizeof(xe->XE.Heap.datasym)-1]
+ == 0);
+ }
+ }
+ break;
}
case XE_Arith:
- return sizeof(XError);
+ break;
case XE_SysParam:
- return sizeof(XError);
+ break;
default:
VG_(tool_panic)("update_extra");
}
+ return sizeof(XError);
}
Bool pc_is_recognised_suppression ( Char* name, Supp *su )
diff --git a/exp-ptrcheck/pc_common.h b/exp-ptrcheck/pc_common.h
index 023307f4b..9c440d167 100644
--- a/exp-ptrcheck/pc_common.h
+++ b/exp-ptrcheck/pc_common.h
@@ -47,8 +47,9 @@ void h_record_arith_error( Seg* seg1, Seg* seg2, HChar* opname );
void h_record_sysparam_error( ThreadId tid, CorePart part, Char* s,
Addr lo, Addr hi, Seg* seglo, Seg* seghi );
-Bool pc_eq_Error ( VgRes res, Error* e1, Error* e2 );
-void pc_pp_Error ( Error* err );
+Bool pc_eq_Error ( VgRes res, Error* e1, Error* e2 );
+void pc_before_pp_Error ( Error* err );
+void pc_pp_Error ( Error* err );
UInt pc_update_Error_extra ( Error* err );
Bool pc_is_recognised_suppression ( Char* name, Supp *su );
Bool pc_read_extra_suppression_info ( Int fd, Char* buf,
diff --git a/exp-ptrcheck/pc_main.c b/exp-ptrcheck/pc_main.c
index 6f44bbfd3..436dba013 100644
--- a/exp-ptrcheck/pc_main.c
+++ b/exp-ptrcheck/pc_main.c
@@ -130,11 +130,14 @@ static void pc_post_clo_init ( void )
# elif defined(VGA_ppc32) || defined(VGA_ppc64)
if (VG_(clo_verbosity) >= 1 && sg_clo_enable_sg_checks) {
VG_(message)(Vg_UserMsg,
- "WARNING: exp-ptrcheck on ppc32/ppc64 platforms: stack and global array");
+ "WARNING: exp-ptrcheck on ppc32/ppc64 platforms: "
+ "stack and global array\n");
VG_(message)(Vg_UserMsg,
- "WARNING: checking is not currently supported. Only heap checking is");
+ "WARNING: checking is not currently supported. "
+ "Only heap checking is\n");
VG_(message)(Vg_UserMsg,
- "WARNING: supported. Disabling s/g checks (like --enable-sg-checks=no).");
+ "WARNING: supported. Disabling s/g checks "
+ "(like --enable-sg-checks=no).\n");
}
sg_clo_enable_sg_checks = False;
# else
@@ -179,6 +182,7 @@ static void pc_pre_clo_init(void)
VG_(needs_core_errors) ();
VG_(needs_tool_errors) (pc_eq_Error,
+ pc_before_pp_Error,
pc_pp_Error,
True,/*show TIDs for errors*/
pc_update_Error_extra,
@@ -188,6 +192,8 @@ static void pc_pre_clo_init(void)
pc_get_error_name,
pc_print_extra_suppression_info);
+ VG_(needs_xml_output) ();
+
VG_(needs_syscall_wrapper)( h_pre_syscall,
h_post_syscall );
diff --git a/exp-ptrcheck/sg_main.c b/exp-ptrcheck/sg_main.c
index 85d8078ea..27ed78207 100644
--- a/exp-ptrcheck/sg_main.c
+++ b/exp-ptrcheck/sg_main.c
@@ -223,16 +223,16 @@ static Word StackBlocks__cmp ( XArray* fb1s, XArray* fb2s )
static void pp_StackBlocks ( XArray* sbs )
{
Word i, n = VG_(sizeXA)( sbs );
- VG_(message)(Vg_DebugMsg, "<<< STACKBLOCKS" );
+ VG_(message)(Vg_DebugMsg, "<<< STACKBLOCKS\n" );
for (i = 0; i < n; i++) {
StackBlock* sb = (StackBlock*)VG_(indexXA)( sbs, i );
VG_(message)(Vg_DebugMsg,
- " StackBlock{ off %ld szB %lu spRel:%c isVec:%c \"%s\" }",
+ " StackBlock{ off %ld szB %lu spRel:%c isVec:%c \"%s\" }\n",
sb->base, sb->szB, sb->spRel ? 'Y' : 'N',
sb->isVec ? 'Y' : 'N', &sb->name[0]
);
}
- VG_(message)(Vg_DebugMsg, ">>> STACKBLOCKS" );
+ VG_(message)(Vg_DebugMsg, ">>> STACKBLOCKS\n" );
}
@@ -345,12 +345,12 @@ static XArray* /* of StackBlock */
if (moans > 0 && !VG_(clo_xml)) {
moans--;
VG_(message)(Vg_UserMsg, "Warning: bogus DWARF3 info: "
- "overlapping stack blocks");
+ "overlapping stack blocks\n");
if (VG_(clo_verbosity) >= 2)
pp_StackBlocks(orig);
if (moans == 0)
VG_(message)(Vg_UserMsg, "Further instances of this "
- "message will not be shown" );
+ "message will not be shown\n" );
}
VG_(dropTailXA)( orig, VG_(sizeXA)( orig ));
break;
@@ -740,7 +740,7 @@ static void add_block_to_GlobalTree (
if (already_present && moans > 0 && !VG_(clo_xml)) {
moans--;
VG_(message)(Vg_UserMsg, "Warning: bogus DWARF3 info: "
- "overlapping global blocks");
+ "overlapping global blocks\n");
if (VG_(clo_verbosity) >= 2) {
GlobalTree__pp( gitree,
"add_block_to_GlobalTree: non-exact duplicate" );
@@ -750,7 +750,7 @@ static void add_block_to_GlobalTree (
}
if (moans == 0)
VG_(message)(Vg_UserMsg, "Further instances of this "
- "message will not be shown" );
+ "message will not be shown\n" );
}
/* tl_assert(!already_present); */
}
@@ -1830,7 +1830,7 @@ void shadowStack_new_frame ( ThreadId tid,
if (0 && (sb || gb))
VG_(message)(Vg_DebugMsg,
"exp-sgcheck: new max tree sizes: "
- "StackTree %ld, GlobalTree %ld",
+ "StackTree %ld, GlobalTree %ld\n",
stats__max_sitree_size, stats__max_gitree_size );
}
} else {
@@ -2454,32 +2454,32 @@ void sg_fini(Int exitcode)
{
if (VG_(clo_verbosity) >= 2) {
VG_(message)(Vg_DebugMsg,
- " sg_: %'llu total accesses, of which:", stats__total_accesses);
+ " sg_: %'llu total accesses, of which:\n", stats__total_accesses);
VG_(message)(Vg_DebugMsg,
- " sg_: stack0: %'12llu classify",
+ " sg_: stack0: %'12llu classify\n",
stats__classify_Stack0);
VG_(message)(Vg_DebugMsg,
- " sg_: stackN: %'12llu classify",
+ " sg_: stackN: %'12llu classify\n",
stats__classify_StackN);
VG_(message)(Vg_DebugMsg,
- " sg_: global: %'12llu classify",
+ " sg_: global: %'12llu classify\n",
stats__classify_Global);
VG_(message)(Vg_DebugMsg,
- " sg_: unknown: %'12llu classify",
+ " sg_: unknown: %'12llu classify\n",
stats__classify_Unknown);
VG_(message)(Vg_DebugMsg,
- " sg_: %'llu Invars preened, of which %'llu changed",
+ " sg_: %'llu Invars preened, of which %'llu changed\n",
stats__Invars_preened, stats__Invars_changed);
VG_(message)(Vg_DebugMsg,
- " sg_: t_i_b_MT: %'12llu", stats__t_i_b_empty);
+ " sg_: t_i_b_MT: %'12llu\n", stats__t_i_b_empty);
VG_(message)(Vg_DebugMsg,
- " sg_: qcache: %'llu searches, %'llu probes, %'llu misses",
+ " sg_: qcache: %'llu searches, %'llu probes, %'llu misses\n",
stats__qcache_queries, stats__qcache_probes, stats__qcache_misses);
VG_(message)(Vg_DebugMsg,
- " sg_: htab-fast: %'llu hits",
+ " sg_: htab-fast: %'llu hits\n",
stats__htab_fast);
VG_(message)(Vg_DebugMsg,
- " sg_: htab-slow: %'llu searches, %'llu probes, %'llu resizes",
+ " sg_: htab-slow: %'llu searches, %'llu probes, %'llu resizes\n",
stats__htab_searches, stats__htab_probes, stats__htab_resizes);
}
}
diff --git a/exp-ptrcheck/tests/Makefile.am b/exp-ptrcheck/tests/Makefile.am
index 8a127899f..02c7d5690 100644
--- a/exp-ptrcheck/tests/Makefile.am
+++ b/exp-ptrcheck/tests/Makefile.am
@@ -23,6 +23,7 @@ EXTRA_DIST = \
hackedbz2.stderr.exp-glibc28-amd64 \
hp_bounds.vgtest hp_bounds.stderr.exp \
hp_dangle.vgtest hp_dangle.stderr.exp \
+ hsg.vgtest hsg.stdout.exp hsg.stderr.exp \
idiv.vgtest-disabled idiv.stderr.exp \
imul.vgtest-disabled imul.stderr.exp \
justify.vgtest justify.stderr.exp \
@@ -61,7 +62,7 @@ EXTRA_DIST = \
check_PROGRAMS = \
add and arith bad_percentify base cmp fp \
globalerr hackedbz2 \
- hp_bounds hp_dangle idiv imul \
+ hp_bounds hp_dangle hsg idiv imul \
justify mm not neg or partial \
preen_invars preen_invars_so.so \
pth_create pth_specific realloc \
diff --git a/exp-ptrcheck/tests/hsg.c b/exp-ptrcheck/tests/hsg.c
new file mode 100644
index 000000000..7f497b460
--- /dev/null
+++ b/exp-ptrcheck/tests/hsg.c
@@ -0,0 +1,48 @@
+
+/* A simple test to demonstrate heap, stack, and global overrun
+ detection. */
+
+#include
+#include
+
+short ga[100];
+
+__attribute__((noinline))
+int addup_wrongly ( short* arr )
+{
+ int sum = 0, i;
+ for (i = 0; i <= 100; i++)
+ sum += (int)arr[i];
+ return sum;
+}
+
+__attribute__((noinline))
+int do_other_stuff ( void )
+{
+ short la[100];
+ return 123 + addup_wrongly(la);
+}
+
+__attribute__((noinline))
+int do_stupid_malloc_stuff ( void )
+{
+ int sum = 0;
+ unsigned char* duh = malloc(100 * sizeof(char));
+ sum += duh[-1];
+ free(duh);
+ sum += duh[50];
+ return sum;
+}
+
+int main ( void )
+{
+ long s = addup_wrongly(ga);
+ s += do_other_stuff();
+ s += do_stupid_malloc_stuff();
+ if (s == 123456789) {
+ fprintf(stdout, "well, i never!\n");
+ } else {
+ fprintf(stdout, "boringly as expected\n");
+ }
+ return 0;
+}
diff --git a/exp-ptrcheck/tests/hsg.stderr.exp b/exp-ptrcheck/tests/hsg.stderr.exp
new file mode 100644
index 000000000..50180bea5
--- /dev/null
+++ b/exp-ptrcheck/tests/hsg.stderr.exp
@@ -0,0 +1,231 @@
+
+
+
+
+4
+exp-ptrcheck
+
+
+ ...
+ ...
+ ...
+ ...
+ ...
+ ...
+ ...
+
+
+...
+...
+exp-ptrcheck
+
+
+ ...
+
+ ./hsg
+
+
+
+
+ RUNNING
+
+
+
+
+ 0x........
+ ...
+ SorG
+ Invalid read of size 2
+
+
+ 0x........
+ ...
+ addup_wrongly
+ ...
+ hsg.c
+ ...
+
+
+ 0x........
+ ...
+ main
+ ...
+ hsg.c
+ ...
+
+
+ Address 0x........ expected vs actual:
+ Expected: global array "ga" in object with soname "NONE"
+ Actual: unknown
+
+
+
+ 0x........
+ ...
+ SorG
+ Invalid read of size 2
+
+
+ 0x........
+ ...
+ addup_wrongly
+ ...
+ hsg.c
+ ...
+
+
+ 0x........
+ ...
+ do_other_stuff
+ ...
+ hsg.c
+ ...
+
+
+ 0x........
+ ...
+ main
+ ...
+ hsg.c
+ ...
+
+
+ Address 0x........ expected vs actual:
+ Expected: stack array "la" in frame 1 back from here
+ Actual: unknown
+
+
+
+ 0x........
+ ...
+ Heap
+ Invalid read of size 1
+
+
+ 0x........
+ ...
+ do_stupid_malloc_stuff
+ ...
+ hsg.c
+ ...
+
+
+ 0x........
+ ...
+ main
+ ...
+ hsg.c
+ ...
+
+
+ Address 0x........ is 1 bytes before the accessing pointer's
+ legitimate range, a block of size 100 alloc'd
+
+
+ 0x........
+ ...
+ malloc
+ ...
+ vg_replace_malloc.c
+ ...
+
+
+ 0x........
+ ...
+ do_stupid_malloc_stuff
+ ...
+ hsg.c
+ ...
+
+
+ 0x........
+ ...
+ main
+ ...
+ hsg.c
+ ...
+
+
+
+
+
+ 0x........
+ ...
+ Heap
+ Invalid read of size 1
+
+
+ 0x........
+ ...
+ do_stupid_malloc_stuff
+ ...
+ hsg.c
+ ...
+
+
+ 0x........
+ ...
+ main
+ ...
+ hsg.c
+ ...
+
+
+ Address 0x........ is 50 bytes inside the accessing pointer's
+ once-legitimate range, a block of size 100 free'd
+
+
+ 0x........
+ ...
+ free
+ ...
+ vg_replace_malloc.c
+ ...
+
+
+ 0x........
+ ...
+ do_stupid_malloc_stuff
+ ...
+ hsg.c
+ ...
+
+
+ 0x........
+ ...
+ main
+ ...
+ hsg.c
+ ...
+
+
+
+
+
+ FINISHED
+
+
+
+
+
+ ...
+ 0x........
+
+
+ ...
+ 0x........
+
+
+ ...
+ 0x........
+
+
+ ...
+ 0x........
+
+
+
+...
+
+
+
diff --git a/exp-ptrcheck/tests/hsg.stdout.exp b/exp-ptrcheck/tests/hsg.stdout.exp
new file mode 100644
index 000000000..e5b8e6d67
--- /dev/null
+++ b/exp-ptrcheck/tests/hsg.stdout.exp
@@ -0,0 +1 @@
+boringly as expected
diff --git a/exp-ptrcheck/tests/hsg.vgtest b/exp-ptrcheck/tests/hsg.vgtest
new file mode 100644
index 000000000..663a523db
--- /dev/null
+++ b/exp-ptrcheck/tests/hsg.vgtest
@@ -0,0 +1,3 @@
+prog: hsg
+vgopts: --xml=yes --xml-fd=2 --log-file=/dev/null
+stderr_filter: ../../memcheck/tests/filter_xml
diff --git a/exp-ptrcheck/tests/supp.c b/exp-ptrcheck/tests/supp.c
index 9d211b950..97f778837 100644
--- a/exp-ptrcheck/tests/supp.c
+++ b/exp-ptrcheck/tests/supp.c
@@ -8,12 +8,12 @@
int main(void)
{
- int i = 11;
+ int i = 11; int fd = open("/dev/null", O_WRONLY);
char* buf = malloc(sizeof(char) * 6);
char c = buf[-1]; // LoadStoreErr
char* x = buf + (long)buf; // ArithErr
char* y = (char*)((long)buf * i); // AsmErr
- write(-1, buf+3, 5); // SysParamErr
-
+ write(fd, buf+3, 5); // SysParamErr
+ close(fd);
return x-y+c;
}
diff --git a/exp-ptrcheck/tests/supp.stderr.exp b/exp-ptrcheck/tests/supp.stderr.exp
index ef8f81138..5d219e399 100644
--- a/exp-ptrcheck/tests/supp.stderr.exp
+++ b/exp-ptrcheck/tests/supp.stderr.exp
@@ -1,4 +1,10 @@
-Warning: invalid file descriptor -1 in syscall write()
+Syscall param write(buf) is non-contiguous
+ at 0x........: write (in /...libc...)
+ by 0x........: main (supp.c:16)
+ First byte (0x........) is 3 bytes inside a 6-byte block alloc'd
+ at 0x........: malloc (vg_replace_malloc.c:...)
+ by 0x........: main (supp.c:12)
+ Last byte is not inside a known block
-ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
+ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)