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)