From: Julian Seward Date: Wed, 15 Jul 2009 14:50:02 +0000 (+0000) Subject: Merge helgrind/ changes from branches/MESSAGING_TIDYUP r10464. X-Git-Tag: svn/VALGRIND_3_5_0~380 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=d6407ffc6351ced5f93e7ab9ab12861891e733a9;p=thirdparty%2Fvalgrind.git Merge helgrind/ changes from branches/MESSAGING_TIDYUP r10464. See trunk r10465 commit message for details. git-svn-id: svn://svn.valgrind.org/valgrind/trunk@10468 --- diff --git a/helgrind/hg_errors.c b/helgrind/hg_errors.c index fbb499bf30..1d1acc2244 100644 --- a/helgrind/hg_errors.c +++ b/helgrind/hg_errors.c @@ -39,6 +39,7 @@ #include "pub_tool_xarray.h" #include "pub_tool_debuginfo.h" #include "pub_tool_threadstate.h" +#include "pub_tool_options.h" // VG_(clo_xml) #include "hg_basics.h" #include "hg_wordset.h" @@ -48,17 +49,7 @@ /*----------------------------------------------------------------*/ -/*--- ---*/ -/*----------------------------------------------------------------*/ - -/* This has to do with printing error messages. See comments on - announce_threadset() and summarise_threadset(). Perhaps it - should be a command line option. */ -#define N_THREADS_TO_ANNOUNCE 5 - - -/*----------------------------------------------------------------*/ -/*--- Error management ---*/ +/*--- Error management -- storage ---*/ /*----------------------------------------------------------------*/ /* maps (by value) strings to a copy of them in ARENA_TOOL */ @@ -168,7 +159,6 @@ static Lock* mk_LockP_from_LockN ( Lock* lkn ) typedef enum { XE_Race=1101, // race - XE_FreeMemLock, // freeing memory containing a locked lock XE_UnlockUnlocked, // unlocking a not-locked lock XE_UnlockForeign, // unlocking a lock held by some other thread XE_UnlockBogus, // unlocking an address not known to be a lock @@ -193,13 +183,9 @@ typedef Thread* mb_confaccthr; Int mb_confaccSzB; Bool mb_confaccIsW; - Char descr1[96]; - Char descr2[96]; + XArray* descr1; /* XArray* of HChar */ + XArray* descr2; /* XArray* of HChar */ } Race; - struct { - Thread* thr; /* doing the freeing */ - Lock* lock; /* lock which is locked */ - } FreeMemLock; struct { Thread* thr; /* doing the unlocking */ Lock* lock; /* lock (that is already unlocked) */ @@ -265,6 +251,7 @@ UInt HG_(update_extra) ( Error* err ) //} if (xe->tag == XE_Race) { + /* See if we can come up with a source level description of the raced-upon address. This is potentially expensive, which is why it's only done at the update_extra point, not when the @@ -274,17 +261,38 @@ UInt HG_(update_extra) ( Error* err ) if (0) VG_(printf)("HG_(update_extra): " "%d conflicting-event queries\n", xxx); - tl_assert(sizeof(xe->XE.Race.descr1) == sizeof(xe->XE.Race.descr2)); - if (VG_(get_data_description)( - &xe->XE.Race.descr1[0], - &xe->XE.Race.descr2[0], - sizeof(xe->XE.Race.descr1)-1, - xe->XE.Race.data_addr )) { - tl_assert( xe->XE.Race.descr1 - [ sizeof(xe->XE.Race.descr1)-1 ] == 0); - tl_assert( xe->XE.Race.descr2 - [ sizeof(xe->XE.Race.descr2)-1 ] == 0); + tl_assert(!xe->XE.Race.descr1); + tl_assert(!xe->XE.Race.descr2); + + xe->XE.Race.descr1 + = VG_(newXA)( HG_(zalloc), "hg.update_extra.Race.descr1", + HG_(free), sizeof(HChar) ); + xe->XE.Race.descr2 + = VG_(newXA)( HG_(zalloc), "hg.update_extra.Race.descr2", + HG_(free), sizeof(HChar) ); + + (void) VG_(get_data_description)( xe->XE.Race.descr1, + xe->XE.Race.descr2, + xe->XE.Race.data_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.Race.descr1, 0 ))) { + VG_(deleteXA)( xe->XE.Race.descr1 ); + xe->XE.Race.descr1 = NULL; + } + if (0 == VG_(strlen)( VG_(indexXA)( xe->XE.Race.descr2, 0 ))) { + VG_(deleteXA)( xe->XE.Race.descr2 ); + xe->XE.Race.descr2 = NULL; } + + /* And poke around in the conflicting-event map, to see if we + can rustle up a plausible-looking conflicting memory access + to show. */ { Thr* thrp = NULL; ExeContext* wherep = NULL; Addr acc_addr = xe->XE.Race.data_addr; @@ -347,7 +355,11 @@ void HG_(record_error_Race) ( Thread* thr, xe.XE.Race.thr = thr; tl_assert(isWrite == False || isWrite == True); tl_assert(szB == 8 || szB == 4 || szB == 2 || szB == 1); - xe.XE.Race.descr1[0] = xe.XE.Race.descr2[0] = 0; + /* Skip on the detailed description of the raced-on address at this + point; it's expensive. Leave it for the update_extra function + if we ever make it that far. */ + tl_assert(xe.XE.Race.descr1 == NULL); + tl_assert(xe.XE.Race.descr2 == NULL); // FIXME: tid vs thr // Skip on any of the conflicting-access info at this point. // It's expensive to obtain, and this error is more likely than @@ -364,22 +376,6 @@ void HG_(record_error_Race) ( Thread* thr, XE_Race, data_addr, NULL, &xe ); } -void HG_(record_error_FreeMemLock) ( Thread* thr, Lock* lk ) -{ - XError xe; - tl_assert( HG_(is_sane_Thread)(thr) ); - tl_assert( HG_(is_sane_LockN)(lk) ); - init_XError(&xe); - xe.tag = XE_FreeMemLock; - xe.XE.FreeMemLock.thr = thr; - xe.XE.FreeMemLock.lock = mk_LockP_from_LockN(lk); - // FIXME: tid vs thr - tl_assert( HG_(is_sane_ThreadId)(thr->coretid) ); - tl_assert( thr->coretid != VG_INVALID_THREADID ); - VG_(maybe_record_error)( thr->coretid, - XE_FreeMemLock, 0, NULL, &xe ); -} - void HG_(record_error_UnlockUnlocked) ( Thread* thr, Lock* lk ) { XError xe; @@ -507,9 +503,6 @@ Bool HG_(eq_Error) ( VgRes not_used, Error* e1, Error* e2 ) && (HG_(clo_cmp_race_err_addrs) ? xe1->XE.Race.data_addr == xe2->XE.Race.data_addr : True); - case XE_FreeMemLock: - return xe1->XE.FreeMemLock.thr == xe2->XE.FreeMemLock.thr - && xe1->XE.FreeMemLock.lock == xe2->XE.FreeMemLock.lock; case XE_UnlockUnlocked: return xe1->XE.UnlockUnlocked.thr == xe2->XE.UnlockUnlocked.thr && xe1->XE.UnlockUnlocked.lock == xe2->XE.UnlockUnlocked.lock; @@ -539,158 +532,354 @@ Bool HG_(eq_Error) ( VgRes not_used, Error* e1, Error* e2 ) } +/*----------------------------------------------------------------*/ +/*--- Error management -- printing ---*/ +/*----------------------------------------------------------------*/ + +/* 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 emit_no_f_c ( HChar* format, ... ) +{ + va_list vargs; + va_start(vargs, format); + emit_WRK(format, vargs); + va_end(vargs); +} + + /* Announce (that is, print the point-of-creation) of 'thr'. Only do this once, as we only want to see these announcements once per - thread. */ -static void announce_one_thread ( Thread* thr ) + thread. Returned Bool indicates whether or not an announcement was + made. +*/ +static Bool announce_one_thread ( Thread* thr ) { tl_assert(HG_(is_sane_Thread)(thr)); tl_assert(thr->errmsg_index >= 1); - if (!thr->announced) { + if (thr->announced) + return False; + + if (VG_(clo_xml)) { + + VG_(printf_xml)("\n"); + VG_(printf_xml)(" %d\n", thr->errmsg_index); if (thr->errmsg_index == 1) { tl_assert(thr->created_at == NULL); - VG_(message)(Vg_UserMsg, "Thread #%d is the program's root thread", - thr->errmsg_index); + VG_(printf_xml)(" \n"); + } else { + tl_assert(thr->created_at != NULL); + VG_(pp_ExeContext)( thr->created_at ); + } + VG_(printf_xml)("\n\n"); + + } else { + + if (thr->errmsg_index == 1) { + tl_assert(thr->created_at == NULL); + VG_(message)(Vg_UserMsg, + "Thread #%d is the program's root thread\n", + thr->errmsg_index); } else { tl_assert(thr->created_at != NULL); - VG_(message)(Vg_UserMsg, "Thread #%d was created", + VG_(message)(Vg_UserMsg, "Thread #%d was created\n", thr->errmsg_index); VG_(pp_ExeContext)( thr->created_at ); } - VG_(message)(Vg_UserMsg, ""); - thr->announced = True; + VG_(message)(Vg_UserMsg, "\n"); + + } + + thr->announced = True; + return True; +} + + +/* This is the "this error is due to be printed shortly; so have a + look at it any print any preamble you want" function. We use it to + announce any previously un-announced threads in the upcoming error + message. +*/ +void HG_(before_pp_Error) ( Error* err ) +{ + XError* xe; + tl_assert(err); + xe = (XError*)VG_(get_error_extra)(err); + tl_assert(xe); + + switch (VG_(get_error_kind)(err)) { + case XE_Misc: + announce_one_thread( xe->XE.Misc.thr ); + break; + case XE_LockOrder: + announce_one_thread( xe->XE.LockOrder.thr ); + break; + case XE_PthAPIerror: + announce_one_thread( xe->XE.PthAPIerror.thr ); + break; + case XE_UnlockBogus: + announce_one_thread( xe->XE.UnlockBogus.thr ); + break; + case XE_UnlockForeign: + announce_one_thread( xe->XE.UnlockForeign.thr ); + announce_one_thread( xe->XE.UnlockForeign.owner ); + break; + case XE_UnlockUnlocked: + announce_one_thread( xe->XE.UnlockUnlocked.thr ); + break; + case XE_Race: + announce_one_thread( xe->XE.Race.thr ); + if (xe->XE.Race.mb_confaccthr) + announce_one_thread( xe->XE.Race.mb_confaccthr ); + break; + default: + tl_assert(0); } } void HG_(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); switch (VG_(get_error_kind)(err)) { case XE_Misc: { - tl_assert(xe); tl_assert( HG_(is_sane_Thread)( xe->XE.Misc.thr ) ); - announce_one_thread( xe->XE.Misc.thr ); - VG_(message)(Vg_UserMsg, - "Thread #%d: %s", - (Int)xe->XE.Misc.thr->errmsg_index, - xe->XE.Misc.errstr); - VG_(pp_ExeContext)( VG_(get_error_where)(err) ); + + if (xml) { + + emit( " Misc\n"); + emit( " \n" ); + emit( " Thread #%d: %s\n", + (Int)xe->XE.Misc.thr->errmsg_index, + xe->XE.Misc.errstr ); + emit( " %d\n", + (Int)xe->XE.Misc.thr->errmsg_index ); + emit( " \n" ); + VG_(pp_ExeContext)( VG_(get_error_where)(err) ); + + } else { + + emit( "Thread #%d: %s\n", + (Int)xe->XE.Misc.thr->errmsg_index, + xe->XE.Misc.errstr ); + VG_(pp_ExeContext)( VG_(get_error_where)(err) ); + + } break; } case XE_LockOrder: { - tl_assert(xe); tl_assert( HG_(is_sane_Thread)( xe->XE.LockOrder.thr ) ); - announce_one_thread( xe->XE.LockOrder.thr ); - VG_(message)(Vg_UserMsg, - "Thread #%d: lock order \"%p before %p\" violated", - (Int)xe->XE.LockOrder.thr->errmsg_index, - (void*)xe->XE.LockOrder.before_ga, - (void*)xe->XE.LockOrder.after_ga); - VG_(pp_ExeContext)( VG_(get_error_where)(err) ); - if (xe->XE.LockOrder.before_ec && xe->XE.LockOrder.after_ec) { - VG_(message)(Vg_UserMsg, - " Required order was established by acquisition of lock at %p", - (void*)xe->XE.LockOrder.before_ga); - VG_(pp_ExeContext)( xe->XE.LockOrder.before_ec ); - VG_(message)(Vg_UserMsg, - " followed by a later acquisition of lock at %p", - (void*)xe->XE.LockOrder.after_ga); - VG_(pp_ExeContext)( xe->XE.LockOrder.after_ec ); + + if (xml) { + + emit( " LockOrder\n"); + emit( " \n" ); + emit( " Thread #%d: lock order \"%p before %p\" " + "violated\n", + (Int)xe->XE.LockOrder.thr->errmsg_index, + (void*)xe->XE.LockOrder.before_ga, + (void*)xe->XE.LockOrder.after_ga ); + emit( " %d\n", + (Int)xe->XE.LockOrder.thr->errmsg_index ); + emit( " \n" ); + VG_(pp_ExeContext)( VG_(get_error_where)(err) ); + if (xe->XE.LockOrder.before_ec && xe->XE.LockOrder.after_ec) { + emit( " Required order was established by " + "acquisition of lock at %p\n", + (void*)xe->XE.LockOrder.before_ga ); + VG_(pp_ExeContext)( xe->XE.LockOrder.before_ec ); + emit( " followed by a later acquisition " + "of lock at %p\n", + (void*)xe->XE.LockOrder.after_ga ); + VG_(pp_ExeContext)( xe->XE.LockOrder.after_ec ); + } + + } else { + + emit( "Thread #%d: lock order \"%p before %p\" violated\n", + (Int)xe->XE.LockOrder.thr->errmsg_index, + (void*)xe->XE.LockOrder.before_ga, + (void*)xe->XE.LockOrder.after_ga ); + VG_(pp_ExeContext)( VG_(get_error_where)(err) ); + if (xe->XE.LockOrder.before_ec && xe->XE.LockOrder.after_ec) { + emit( " Required order was established by " + "acquisition of lock at %p\n", + (void*)xe->XE.LockOrder.before_ga ); + VG_(pp_ExeContext)( xe->XE.LockOrder.before_ec ); + emit( " followed by a later acquisition of lock at %p\n", + (void*)xe->XE.LockOrder.after_ga ); + VG_(pp_ExeContext)( xe->XE.LockOrder.after_ec ); + } + } + break; } case XE_PthAPIerror: { - tl_assert(xe); tl_assert( HG_(is_sane_Thread)( xe->XE.PthAPIerror.thr ) ); - announce_one_thread( xe->XE.PthAPIerror.thr ); - VG_(message)(Vg_UserMsg, - "Thread #%d's call to %s failed", - (Int)xe->XE.PthAPIerror.thr->errmsg_index, - xe->XE.PthAPIerror.fnname); - VG_(message)(Vg_UserMsg, - " with error code %ld (%s)", - xe->XE.PthAPIerror.err, - xe->XE.PthAPIerror.errstr); - VG_(pp_ExeContext)( VG_(get_error_where)(err) ); + + if (xml) { + + emit( " PthAPIerror\n"); + emit( " \n" ); + emit_no_f_c( + " Thread #%d's call to %t failed\n", + (Int)xe->XE.PthAPIerror.thr->errmsg_index, + xe->XE.PthAPIerror.fnname ); + emit( " %d\n", + (Int)xe->XE.PthAPIerror.thr->errmsg_index ); + emit( " \n" ); + emit( " with error code %ld (%s)\n", + xe->XE.PthAPIerror.err, xe->XE.PthAPIerror.errstr ); + VG_(pp_ExeContext)( VG_(get_error_where)(err) ); + + } else { + + emit_no_f_c( "Thread #%d's call to %t failed\n", + (Int)xe->XE.PthAPIerror.thr->errmsg_index, + xe->XE.PthAPIerror.fnname ); + emit( " with error code %ld (%s)\n", + xe->XE.PthAPIerror.err, xe->XE.PthAPIerror.errstr ); + VG_(pp_ExeContext)( VG_(get_error_where)(err) ); + + } + break; } case XE_UnlockBogus: { - tl_assert(xe); tl_assert( HG_(is_sane_Thread)( xe->XE.UnlockBogus.thr ) ); - announce_one_thread( xe->XE.UnlockBogus.thr ); - VG_(message)(Vg_UserMsg, - "Thread #%d unlocked an invalid lock at %p ", - (Int)xe->XE.UnlockBogus.thr->errmsg_index, - (void*)xe->XE.UnlockBogus.lock_ga); - VG_(pp_ExeContext)( VG_(get_error_where)(err) ); + + if (xml) { + + emit( " UnlockBogus\n"); + emit( " \n" ); + emit( " Thread #%d unlocked an invalid " + "lock at %p\n", + (Int)xe->XE.UnlockBogus.thr->errmsg_index, + (void*)xe->XE.UnlockBogus.lock_ga ); + emit( " %d\n", + (Int)xe->XE.UnlockBogus.thr->errmsg_index ); + emit( " \n" ); + VG_(pp_ExeContext)( VG_(get_error_where)(err) ); + + } else { + + emit( "Thread #%d unlocked an invalid lock at %p\n", + (Int)xe->XE.UnlockBogus.thr->errmsg_index, + (void*)xe->XE.UnlockBogus.lock_ga ); + VG_(pp_ExeContext)( VG_(get_error_where)(err) ); + + } + break; } case XE_UnlockForeign: { - tl_assert(xe); tl_assert( HG_(is_sane_LockP)( xe->XE.UnlockForeign.lock ) ); tl_assert( HG_(is_sane_Thread)( xe->XE.UnlockForeign.owner ) ); tl_assert( HG_(is_sane_Thread)( xe->XE.UnlockForeign.thr ) ); - announce_one_thread( xe->XE.UnlockForeign.thr ); - announce_one_thread( xe->XE.UnlockForeign.owner ); - VG_(message)(Vg_UserMsg, - "Thread #%d unlocked lock at %p " - "currently held by thread #%d", - (Int)xe->XE.UnlockForeign.thr->errmsg_index, - (void*)xe->XE.UnlockForeign.lock->guestaddr, - (Int)xe->XE.UnlockForeign.owner->errmsg_index ); - VG_(pp_ExeContext)( VG_(get_error_where)(err) ); - if (xe->XE.UnlockForeign.lock->appeared_at) { - VG_(message)(Vg_UserMsg, - " Lock at %p was first observed", - (void*)xe->XE.UnlockForeign.lock->guestaddr); - VG_(pp_ExeContext)( xe->XE.UnlockForeign.lock->appeared_at ); + + if (xml) { + + emit( " UnlockForeign\n"); + emit( " \n" ); + emit( " Thread #%d unlocked lock at %p " + "currently held by thread #%d\n", + (Int)xe->XE.UnlockForeign.thr->errmsg_index, + (void*)xe->XE.UnlockForeign.lock->guestaddr, + (Int)xe->XE.UnlockForeign.owner->errmsg_index ); + emit( " %d\n", + (Int)xe->XE.UnlockForeign.thr->errmsg_index ); + emit( " %d\n", + (Int)xe->XE.UnlockForeign.owner->errmsg_index ); + emit( " \n" ); + VG_(pp_ExeContext)( VG_(get_error_where)(err) ); + + if (xe->XE.UnlockForeign.lock->appeared_at) { + emit( " Lock at %p was first observed\n", + (void*)xe->XE.UnlockForeign.lock->guestaddr ); + VG_(pp_ExeContext)( xe->XE.UnlockForeign.lock->appeared_at ); + } + + } else { + + emit( "Thread #%d unlocked lock at %p " + "currently held by thread #%d\n", + (Int)xe->XE.UnlockForeign.thr->errmsg_index, + (void*)xe->XE.UnlockForeign.lock->guestaddr, + (Int)xe->XE.UnlockForeign.owner->errmsg_index ); + VG_(pp_ExeContext)( VG_(get_error_where)(err) ); + if (xe->XE.UnlockForeign.lock->appeared_at) { + emit( " Lock at %p was first observed\n", + (void*)xe->XE.UnlockForeign.lock->guestaddr ); + VG_(pp_ExeContext)( xe->XE.UnlockForeign.lock->appeared_at ); + } + } + break; } case XE_UnlockUnlocked: { - tl_assert(xe); tl_assert( HG_(is_sane_LockP)( xe->XE.UnlockUnlocked.lock ) ); tl_assert( HG_(is_sane_Thread)( xe->XE.UnlockUnlocked.thr ) ); - announce_one_thread( xe->XE.UnlockUnlocked.thr ); - VG_(message)(Vg_UserMsg, - "Thread #%d unlocked a not-locked lock at %p ", - (Int)xe->XE.UnlockUnlocked.thr->errmsg_index, - (void*)xe->XE.UnlockUnlocked.lock->guestaddr); - VG_(pp_ExeContext)( VG_(get_error_where)(err) ); - if (xe->XE.UnlockUnlocked.lock->appeared_at) { - VG_(message)(Vg_UserMsg, - " Lock at %p was first observed", - (void*)xe->XE.UnlockUnlocked.lock->guestaddr); - VG_(pp_ExeContext)( xe->XE.UnlockUnlocked.lock->appeared_at ); - } - break; - } - case XE_FreeMemLock: { - tl_assert(xe); - tl_assert( HG_(is_sane_LockP)( xe->XE.FreeMemLock.lock ) ); - tl_assert( HG_(is_sane_Thread)( xe->XE.FreeMemLock.thr ) ); - announce_one_thread( xe->XE.FreeMemLock.thr ); - VG_(message)(Vg_UserMsg, - "Thread #%d deallocated location %p " - "containing a locked lock", - (Int)xe->XE.FreeMemLock.thr->errmsg_index, - (void*)xe->XE.FreeMemLock.lock->guestaddr); - VG_(pp_ExeContext)( VG_(get_error_where)(err) ); - if (xe->XE.FreeMemLock.lock->appeared_at) { - VG_(message)(Vg_UserMsg, - " Lock at %p was first observed", - (void*)xe->XE.FreeMemLock.lock->guestaddr); - VG_(pp_ExeContext)( xe->XE.FreeMemLock.lock->appeared_at ); + if (xml) { + + emit( " UnlockUnlocked\n"); + emit( " \n" ); + emit( " Thread #%d unlocked a " + "not-locked lock at %p\n", + (Int)xe->XE.UnlockUnlocked.thr->errmsg_index, + (void*)xe->XE.UnlockUnlocked.lock->guestaddr ); + emit( " %d\n", + (Int)xe->XE.UnlockUnlocked.thr->errmsg_index ); + emit( " \n" ); + VG_(pp_ExeContext)( VG_(get_error_where)(err) ); + if (xe->XE.UnlockUnlocked.lock->appeared_at) { + emit( " Lock at %p was first observed\n", + (void*)xe->XE.UnlockUnlocked.lock->guestaddr ); + VG_(pp_ExeContext)( xe->XE.UnlockUnlocked.lock->appeared_at ); + } + + } else { + + emit( "Thread #%d unlocked a not-locked lock at %p\n", + (Int)xe->XE.UnlockUnlocked.thr->errmsg_index, + (void*)xe->XE.UnlockUnlocked.lock->guestaddr ); + VG_(pp_ExeContext)( VG_(get_error_where)(err) ); + if (xe->XE.UnlockUnlocked.lock->appeared_at) { + emit( " Lock at %p was first observed\n", + (void*)xe->XE.UnlockUnlocked.lock->guestaddr ); + VG_(pp_ExeContext)( xe->XE.UnlockUnlocked.lock->appeared_at ); + } + } + break; } @@ -702,39 +891,79 @@ void HG_(pp_Error) ( Error* err ) szB = xe->XE.Race.szB; err_ga = VG_(get_error_address)(err); - announce_one_thread( xe->XE.Race.thr ); + tl_assert( HG_(is_sane_Thread)( xe->XE.Race.thr )); if (xe->XE.Race.mb_confaccthr) - announce_one_thread( xe->XE.Race.mb_confaccthr ); - VG_(message)(Vg_UserMsg, - "Possible data race during %s of size %d at %#lx by thread #%d", - what, szB, err_ga, (Int)xe->XE.Race.thr->errmsg_index - ); - VG_(pp_ExeContext)( VG_(get_error_where)(err) ); - if (xe->XE.Race.mb_confacc) { - if (xe->XE.Race.mb_confaccthr) { - VG_(message)(Vg_UserMsg, - " This conflicts with a previous %s of size %d by thread #%d", - xe->XE.Race.mb_confaccIsW ? "write" : "read", - xe->XE.Race.mb_confaccSzB, - xe->XE.Race.mb_confaccthr->errmsg_index - ); - } else { - // FIXME: can this ever happen? - VG_(message)(Vg_UserMsg, - " This conflicts with a previous %s of size %d", - xe->XE.Race.mb_confaccIsW ? "write" : "read", - xe->XE.Race.mb_confaccSzB - ); + tl_assert( HG_(is_sane_Thread)( xe->XE.Race.mb_confaccthr )); + + if (xml) { + + /* ------ XML ------ */ + emit( " Race\n" ); + emit( " \n" ); + emit( " Possible data race during %s of size %d " + "at %#lx by thread #%d\n", + what, szB, err_ga, (Int)xe->XE.Race.thr->errmsg_index ); + emit( " %d\n", + (Int)xe->XE.Race.thr->errmsg_index ); + emit( " \n" ); + VG_(pp_ExeContext)( VG_(get_error_where)(err) ); + + if (xe->XE.Race.mb_confacc) { + if (xe->XE.Race.mb_confaccthr) { + emit( " \n"); + emit( " This conflicts with a previous %s of size %d " + "by thread #%d\n", + xe->XE.Race.mb_confaccIsW ? "write" : "read", + xe->XE.Race.mb_confaccSzB, + xe->XE.Race.mb_confaccthr->errmsg_index ); + emit( " %d\n", + xe->XE.Race.mb_confaccthr->errmsg_index); + emit(" \n"); + } else { + // FIXME: can this ever happen? + emit( " This conflicts with a previous %s " + "of size %d\n", + xe->XE.Race.mb_confaccIsW ? "write" : "read", + xe->XE.Race.mb_confaccSzB ); + } + VG_(pp_ExeContext)( xe->XE.Race.mb_confacc ); } - VG_(pp_ExeContext)( xe->XE.Race.mb_confacc ); - } + } else { + + /* ------ Text ------ */ + emit( "Possible data race during %s of size %d " + "at %#lx by thread #%d\n", + what, szB, err_ga, (Int)xe->XE.Race.thr->errmsg_index ); + VG_(pp_ExeContext)( VG_(get_error_where)(err) ); + if (xe->XE.Race.mb_confacc) { + if (xe->XE.Race.mb_confaccthr) { + emit( " This conflicts with a previous %s of size %d " + "by thread #%d\n", + xe->XE.Race.mb_confaccIsW ? "write" : "read", + xe->XE.Race.mb_confaccSzB, + xe->XE.Race.mb_confaccthr->errmsg_index ); + } else { + // FIXME: can this ever happen? + emit( " This conflicts with a previous %s of size %d\n", + xe->XE.Race.mb_confaccIsW ? "write" : "read", + xe->XE.Race.mb_confaccSzB ); + } + VG_(pp_ExeContext)( xe->XE.Race.mb_confacc ); + } + + } - /* If we have a better description of the address, show it. */ - if (xe->XE.Race.descr1[0] != 0) - VG_(message)(Vg_UserMsg, " %s", &xe->XE.Race.descr1[0]); - if (xe->XE.Race.descr2[0] != 0) - VG_(message)(Vg_UserMsg, " %s", &xe->XE.Race.descr2[0]); + /* 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 (xe->XE.Race.descr1) + emit( "%s%s\n", xml ? " " : " ", + (HChar*)VG_(indexXA)( xe->XE.Race.descr1, 0 ) ); + if (xe->XE.Race.descr2) + emit( "%s%s\n", xml ? " " : " ", + (HChar*)VG_(indexXA)( xe->XE.Race.descr2, 0 ) ); break; /* case XE_Race */ } /* case XE_Race */ @@ -748,7 +977,6 @@ Char* HG_(get_error_name) ( Error* err ) { switch (VG_(get_error_kind)(err)) { case XE_Race: return "Race"; - case XE_FreeMemLock: return "FreeMemLock"; case XE_UnlockUnlocked: return "UnlockUnlocked"; case XE_UnlockForeign: return "UnlockForeign"; case XE_UnlockBogus: return "UnlockBogus"; @@ -790,7 +1018,6 @@ Bool HG_(error_matches_suppression) ( Error* err, Supp* su ) { switch (VG_(get_supp_kind)(su)) { case XS_Race: return VG_(get_error_kind)(err) == XE_Race; - case XS_FreeMemLock: return VG_(get_error_kind)(err) == XE_FreeMemLock; case XS_UnlockUnlocked: return VG_(get_error_kind)(err) == XE_UnlockUnlocked; case XS_UnlockForeign: return VG_(get_error_kind)(err) == XE_UnlockForeign; case XS_UnlockBogus: return VG_(get_error_kind)(err) == XE_UnlockBogus; diff --git a/helgrind/hg_errors.h b/helgrind/hg_errors.h index a45173a4f8..9bb6502c09 100644 --- a/helgrind/hg_errors.h +++ b/helgrind/hg_errors.h @@ -35,9 +35,10 @@ /* The standard bundle of error management functions that we are required to present to the core/tool interface at startup. */ -Bool HG_(eq_Error) ( VgRes not_used, Error* e1, Error* e2 ); -void HG_(pp_Error) ( Error* err ); -UInt HG_(update_extra) ( Error* err ); +Bool HG_(eq_Error) ( VgRes not_used, Error* e1, Error* e2 ); +void HG_(before_pp_Error) ( Error* err ); +void HG_(pp_Error) ( Error* err ); +UInt HG_(update_extra) ( Error* err ); Bool HG_(recognised_suppression) ( Char* name, Supp *su ); Bool HG_(read_extra_suppression_info) ( Int fd, Char* buf, Int nBuf, Supp* su ); @@ -49,7 +50,6 @@ void HG_(print_extra_suppression_info) ( Error* err ); void HG_(record_error_Race) ( Thread* thr, Addr data_addr, Int szB, Bool isWrite, ExeContext* mb_lastlock ); -void HG_(record_error_FreeMemLock) ( Thread* thr, Lock* lk ); void HG_(record_error_UnlockUnlocked) ( Thread*, Lock* ); void HG_(record_error_UnlockForeign) ( Thread*, Thread*, Lock* ); void HG_(record_error_UnlockBogus) ( Thread*, Addr ); diff --git a/helgrind/hg_main.c b/helgrind/hg_main.c index 9080ca6d5b..712a9454d6 100644 --- a/helgrind/hg_main.c +++ b/helgrind/hg_main.c @@ -4023,7 +4023,7 @@ static Bool hg_process_cmd_line_option ( Char* arg ) if (6 != VG_(strlen)(tmp_str)) { VG_(message)(Vg_UserMsg, - "--hg-sanity-flags argument must have 6 digits"); + "--hg-sanity-flags argument must have 6 digits\n"); return False; } for (j = 0; j < 6; j++) { @@ -4031,7 +4031,7 @@ static Bool hg_process_cmd_line_option ( Char* arg ) else if ('1' == tmp_str[j]) HG_(clo_sanity_flags) |= (1 << (6-1-j)); else { VG_(message)(Vg_UserMsg, "--hg-sanity-flags argument can " - "only contain 0s and 1s"); + "only contain 0s and 1s\n"); return False; } } @@ -4192,6 +4192,7 @@ static void hg_pre_clo_init ( void ) VG_(needs_core_errors) (); VG_(needs_tool_errors) (HG_(eq_Error), + HG_(before_pp_Error), HG_(pp_Error), False,/*show TIDs for errors*/ HG_(update_extra), @@ -4201,6 +4202,8 @@ static void hg_pre_clo_init ( void ) HG_(get_error_name), HG_(print_extra_suppression_info)); + VG_(needs_xml_output) (); + VG_(needs_command_line_options)(hg_process_cmd_line_option, hg_print_usage, hg_print_debug_usage); diff --git a/helgrind/libhb_core.c b/helgrind/libhb_core.c index 6deccf0596..d51c04fe71 100644 --- a/helgrind/libhb_core.c +++ b/helgrind/libhb_core.c @@ -2289,7 +2289,7 @@ static void vts_tab__do_GC ( Bool show_stats ) static UInt ctr = 0; tl_assert(nTab > 0); VG_(message)(Vg_DebugMsg, - "libhb: VTS GC: #%u old size %lu live %lu (%2llu%%)", + "libhb: VTS GC: #%u old size %lu live %lu (%2llu%%)\n", ctr++, nTab, nLive, (100ULL * (ULong)nLive) / (ULong)nTab); } } @@ -3484,7 +3484,7 @@ static void event_map_maybe_GC ( void ) if (VG_(clo_verbosity) > 1) { VG_(message)(Vg_DebugMsg, "libhb: EvM GC: delete generations %lu and below, " - "retaining %lu entries", + "retaining %lu entries\n", maxGen, retained ); } @@ -3510,7 +3510,7 @@ static void event_map_maybe_GC ( void ) if (VG_(clo_verbosity) > 1) { VG_(message)(Vg_DebugMsg, "libhb: EvM GC: randomly delete half the entries, " - "retaining %lu entries", + "retaining %lu entries\n", retained ); } diff --git a/helgrind/tests/Makefile.am b/helgrind/tests/Makefile.am index 8dba343b48..2d5aa289ef 100644 --- a/helgrind/tests/Makefile.am +++ b/helgrind/tests/Makefile.am @@ -30,6 +30,8 @@ EXTRA_DIST = \ tc05_simple_race.stderr.exp \ tc06_two_races.vgtest tc06_two_races.stdout.exp \ tc06_two_races.stderr.exp \ + tc06_two_races_xml.vgtest tc06_two_races_xml.stdout.exp \ + tc06_two_races_xml.stderr.exp \ tc07_hbl1.vgtest tc07_hbl1.stdout.exp tc07_hbl1.stderr.exp \ tc08_hbl2.vgtest tc08_hbl2.stdout.exp tc08_hbl2.stderr.exp \ tc09_bad_unlock.vgtest tc09_bad_unlock.stdout.exp \ diff --git a/helgrind/tests/tc06_two_races_xml.stderr.exp b/helgrind/tests/tc06_two_races_xml.stderr.exp new file mode 100644 index 0000000000..59f34e8d06 --- /dev/null +++ b/helgrind/tests/tc06_two_races_xml.stderr.exp @@ -0,0 +1,318 @@ + + + + +4 +helgrind + + + ... + ... + ... + ... + ... + ... + + +... +... +helgrind + + + ... + + ./tc06_two_races + + + + + RUNNING + + + + + 1 + + + + + 2 + + + 0x........ + ... + clone + + + 0x........ + ... + do_clone + + + 0x........ + ... + pthread_create@@GLIBC_2.2.5 + + + 0x........ + ... + pthread_create@* + ... + hg_intercepts.c + ... + + + 0x........ + ... + main + ... + tc06_two_races.c + ... + + + + + + 0x........ + ... + Race + + Possible data race during read of size 4 at 0x........ by thread #x + 1 + + + + 0x........ + ... + main + ... + tc06_two_races.c + ... + + + + This conflicts with a previous write of size 4 by thread #x + 2 + + + + 0x........ + ... + child_fn + ... + tc06_two_races.c + ... + + + 0x........ + ... + mythread_wrapper + ... + hg_intercepts.c + ... + + + 0x........ + ... + start_thread + + + 0x........ + ... + clone + + + Location 0x........ is 0 bytes inside global var "unprot1" + declared at tc06_two_races.c:9 tc06_two_races.c ... + + + + 0x........ + ... + Race + + Possible data race during write of size 4 at 0x........ by thread #x + 1 + + + + 0x........ + ... + main + ... + tc06_two_races.c + ... + + + + This conflicts with a previous write of size 4 by thread #x + 2 + + + + 0x........ + ... + child_fn + ... + tc06_two_races.c + ... + + + 0x........ + ... + mythread_wrapper + ... + hg_intercepts.c + ... + + + 0x........ + ... + start_thread + + + 0x........ + ... + clone + + + Location 0x........ is 0 bytes inside global var "unprot1" + declared at tc06_two_races.c:9 tc06_two_races.c ... + + + + 0x........ + ... + Race + + Possible data race during read of size 4 at 0x........ by thread #x + 1 + + + + 0x........ + ... + main + ... + tc06_two_races.c + ... + + + + This conflicts with a previous write of size 4 by thread #x + 2 + + + + 0x........ + ... + child_fn + ... + tc06_two_races.c + ... + + + 0x........ + ... + mythread_wrapper + ... + hg_intercepts.c + ... + + + 0x........ + ... + start_thread + + + 0x........ + ... + clone + + + Location 0x........ is 0 bytes inside global var "unprot2" + declared at tc06_two_races.c:9 tc06_two_races.c ... + + + + 0x........ + ... + Race + + Possible data race during write of size 4 at 0x........ by thread #x + 1 + + + + 0x........ + ... + main + ... + tc06_two_races.c + ... + + + + This conflicts with a previous write of size 4 by thread #x + 2 + + + + 0x........ + ... + child_fn + ... + tc06_two_races.c + ... + + + 0x........ + ... + mythread_wrapper + ... + hg_intercepts.c + ... + + + 0x........ + ... + start_thread + + + 0x........ + ... + clone + + + Location 0x........ is 0 bytes inside global var "unprot2" + declared at tc06_two_races.c:9 tc06_two_races.c ... + + + + FINISHED + + + + + + ... + 0x........ + + + ... + 0x........ + + + ... + 0x........ + + + ... + 0x........ + + + +... + + + diff --git a/helgrind/tests/tc06_two_races_xml.stdout.exp b/helgrind/tests/tc06_two_races_xml.stdout.exp new file mode 100644 index 0000000000..e69de29bb2 diff --git a/helgrind/tests/tc06_two_races_xml.vgtest b/helgrind/tests/tc06_two_races_xml.vgtest new file mode 100644 index 0000000000..26f3e8145b --- /dev/null +++ b/helgrind/tests/tc06_two_races_xml.vgtest @@ -0,0 +1,3 @@ +prog: tc06_two_races +vgopts: --read-var-info=yes --xml=yes --xml-fd=2 --log-file=/dev/null +stderr_filter: ../../memcheck/tests/filter_xml diff --git a/helgrind/tests/tc09_bad_unlock.stderr.exp-glibc23-amd64 b/helgrind/tests/tc09_bad_unlock.stderr.exp-glibc23-amd64 index d78d98a58c..c99424eaf4 100644 --- a/helgrind/tests/tc09_bad_unlock.stderr.exp-glibc23-amd64 +++ b/helgrind/tests/tc09_bad_unlock.stderr.exp-glibc23-amd64 @@ -1,7 +1,7 @@ Thread #x is the program's root thread -Thread #x unlocked a not-locked lock at 0x........ +Thread #x unlocked a not-locked lock at 0x........ at 0x........: pthread_mutex_unlock (hg_intercepts.c:...) by 0x........: nearly_main (tc09_bad_unlock.c:27) by 0x........: main (tc09_bad_unlock.c:49) @@ -26,7 +26,7 @@ Thread #x unlocked lock at 0x........ currently held by thread #x by 0x........: nearly_main (tc09_bad_unlock.c:31) by 0x........: main (tc09_bad_unlock.c:49) -Thread #x unlocked an invalid lock at 0x........ +Thread #x unlocked an invalid lock at 0x........ at 0x........: pthread_mutex_unlock (hg_intercepts.c:...) by 0x........: nearly_main (tc09_bad_unlock.c:41) by 0x........: main (tc09_bad_unlock.c:49) @@ -39,7 +39,7 @@ Thread #x deallocated location 0x........ containing a locked lock by 0x........: nearly_main (tc09_bad_unlock.c:31) by 0x........: main (tc09_bad_unlock.c:49) -Thread #x unlocked a not-locked lock at 0x........ +Thread #x unlocked a not-locked lock at 0x........ at 0x........: pthread_mutex_unlock (hg_intercepts.c:...) by 0x........: nearly_main (tc09_bad_unlock.c:27) by 0x........: main (tc09_bad_unlock.c:50) @@ -64,7 +64,7 @@ Thread #x unlocked lock at 0x........ currently held by thread #x by 0x........: nearly_main (tc09_bad_unlock.c:31) by 0x........: main (tc09_bad_unlock.c:50) -Thread #x unlocked an invalid lock at 0x........ +Thread #x unlocked an invalid lock at 0x........ at 0x........: pthread_mutex_unlock (hg_intercepts.c:...) by 0x........: nearly_main (tc09_bad_unlock.c:41) by 0x........: main (tc09_bad_unlock.c:50) diff --git a/helgrind/tests/tc09_bad_unlock.stderr.exp-glibc25-amd64 b/helgrind/tests/tc09_bad_unlock.stderr.exp-glibc25-amd64 index 51ff990b01..12663ad6c8 100644 --- a/helgrind/tests/tc09_bad_unlock.stderr.exp-glibc25-amd64 +++ b/helgrind/tests/tc09_bad_unlock.stderr.exp-glibc25-amd64 @@ -1,7 +1,7 @@ Thread #x is the program's root thread -Thread #x unlocked a not-locked lock at 0x........ +Thread #x unlocked a not-locked lock at 0x........ at 0x........: pthread_mutex_unlock (hg_intercepts.c:...) by 0x........: nearly_main (tc09_bad_unlock.c:27) by 0x........: main (tc09_bad_unlock.c:49) @@ -26,7 +26,7 @@ Thread #x unlocked lock at 0x........ currently held by thread #x by 0x........: nearly_main (tc09_bad_unlock.c:31) by 0x........: main (tc09_bad_unlock.c:49) -Thread #x unlocked an invalid lock at 0x........ +Thread #x unlocked an invalid lock at 0x........ at 0x........: pthread_mutex_unlock (hg_intercepts.c:...) by 0x........: nearly_main (tc09_bad_unlock.c:41) by 0x........: main (tc09_bad_unlock.c:49) @@ -38,7 +38,7 @@ Thread #x's call to pthread_mutex_unlock failed by 0x........: main (tc09_bad_unlock.c:49) --------------------- -Thread #x unlocked a not-locked lock at 0x........ +Thread #x unlocked a not-locked lock at 0x........ at 0x........: pthread_mutex_unlock (hg_intercepts.c:...) by 0x........: nearly_main (tc09_bad_unlock.c:27) by 0x........: main (tc09_bad_unlock.c:50) @@ -73,7 +73,7 @@ Thread #x unlocked lock at 0x........ currently held by thread #x by 0x........: nearly_main (tc09_bad_unlock.c:31) by 0x........: main (tc09_bad_unlock.c:49) -Thread #x unlocked an invalid lock at 0x........ +Thread #x unlocked an invalid lock at 0x........ at 0x........: pthread_mutex_unlock (hg_intercepts.c:...) by 0x........: nearly_main (tc09_bad_unlock.c:41) by 0x........: main (tc09_bad_unlock.c:50) diff --git a/helgrind/tests/tc09_bad_unlock.stderr.exp-glibc25-x86 b/helgrind/tests/tc09_bad_unlock.stderr.exp-glibc25-x86 index 1e53aa62d1..3409ea120b 100644 --- a/helgrind/tests/tc09_bad_unlock.stderr.exp-glibc25-x86 +++ b/helgrind/tests/tc09_bad_unlock.stderr.exp-glibc25-x86 @@ -1,7 +1,7 @@ Thread #x is the program's root thread -Thread #x unlocked a not-locked lock at 0x........ +Thread #x unlocked a not-locked lock at 0x........ at 0x........: pthread_mutex_unlock (hg_intercepts.c:...) by 0x........: nearly_main (tc09_bad_unlock.c:27) by 0x........: main (tc09_bad_unlock.c:49) @@ -26,7 +26,7 @@ Thread #x unlocked lock at 0x........ currently held by thread #x by 0x........: nearly_main (tc09_bad_unlock.c:31) by 0x........: main (tc09_bad_unlock.c:49) -Thread #x unlocked an invalid lock at 0x........ +Thread #x unlocked an invalid lock at 0x........ at 0x........: pthread_mutex_unlock (hg_intercepts.c:...) by 0x........: nearly_main (tc09_bad_unlock.c:41) by 0x........: main (tc09_bad_unlock.c:49) @@ -45,7 +45,7 @@ Thread #x deallocated location 0x........ containing a locked lock by 0x........: nearly_main (tc09_bad_unlock.c:31) by 0x........: main (tc09_bad_unlock.c:49) -Thread #x unlocked a not-locked lock at 0x........ +Thread #x unlocked a not-locked lock at 0x........ at 0x........: pthread_mutex_unlock (hg_intercepts.c:...) by 0x........: nearly_main (tc09_bad_unlock.c:27) by 0x........: main (tc09_bad_unlock.c:50) @@ -70,7 +70,7 @@ Thread #x unlocked lock at 0x........ currently held by thread #x by 0x........: nearly_main (tc09_bad_unlock.c:31) by 0x........: main (tc09_bad_unlock.c:50) -Thread #x unlocked an invalid lock at 0x........ +Thread #x unlocked an invalid lock at 0x........ at 0x........: pthread_mutex_unlock (hg_intercepts.c:...) by 0x........: nearly_main (tc09_bad_unlock.c:41) by 0x........: main (tc09_bad_unlock.c:50) diff --git a/helgrind/tests/tc10_rec_lock.stderr.exp b/helgrind/tests/tc10_rec_lock.stderr.exp index 7e65ba7658..03c4e7e5f4 100644 --- a/helgrind/tests/tc10_rec_lock.stderr.exp +++ b/helgrind/tests/tc10_rec_lock.stderr.exp @@ -8,7 +8,7 @@ before unlock #3 before unlock #4 Thread #x is the program's root thread -Thread #x unlocked a not-locked lock at 0x........ +Thread #x unlocked a not-locked lock at 0x........ at 0x........: pthread_mutex_unlock (hg_intercepts.c:...) by 0x........: nearly_main (tc10_rec_lock.c:42) by 0x........: main (tc10_rec_lock.c:47) diff --git a/helgrind/tests/tc12_rwl_trivial.stderr.exp b/helgrind/tests/tc12_rwl_trivial.stderr.exp index 5d4f383da0..909bda3bee 100644 --- a/helgrind/tests/tc12_rwl_trivial.stderr.exp +++ b/helgrind/tests/tc12_rwl_trivial.stderr.exp @@ -1,7 +1,7 @@ Thread #x is the program's root thread -Thread #x unlocked a not-locked lock at 0x........ +Thread #x unlocked a not-locked lock at 0x........ at 0x........: pthread_rwlock_unlock (hg_intercepts.c:...) by 0x........: main (tc12_rwl_trivial.c:29) Lock at 0x........ was first observed diff --git a/helgrind/tests/tc20_verifywrap.stderr.exp-glibc25-amd64 b/helgrind/tests/tc20_verifywrap.stderr.exp-glibc25-amd64 index 5d001f5b2d..a6bb62504b 100644 --- a/helgrind/tests/tc20_verifywrap.stderr.exp-glibc25-amd64 +++ b/helgrind/tests/tc20_verifywrap.stderr.exp-glibc25-amd64 @@ -58,7 +58,7 @@ Thread #x's call to pthread_mutex_timedlock failed at 0x........: pthread_mutex_timedlock (hg_intercepts.c:...) by 0x........: main (tc20_verifywrap.c:121) -Thread #x unlocked an invalid lock at 0x........ +Thread #x unlocked an invalid lock at 0x........ at 0x........: pthread_mutex_unlock (hg_intercepts.c:...) by 0x........: main (tc20_verifywrap.c:125) @@ -97,7 +97,7 @@ Thread #x's call to pthread_cond_timedwait failed ---------------- pthread_rwlock_* ---------------- -Thread #x unlocked a not-locked lock at 0x........ +Thread #x unlocked a not-locked lock at 0x........ at 0x........: pthread_rwlock_unlock (hg_intercepts.c:...) by 0x........: main (tc20_verifywrap.c:179) Lock at 0x........ was first observed @@ -107,7 +107,7 @@ Thread #x unlocked a not-locked lock at 0x........ (2) no error on next line (3) ERROR on next line -Thread #x unlocked a not-locked lock at 0x........ +Thread #x unlocked a not-locked lock at 0x........ at 0x........: pthread_rwlock_unlock (hg_intercepts.c:...) by 0x........: main (tc20_verifywrap.c:196) Lock at 0x........ was first observed @@ -119,7 +119,7 @@ Thread #x unlocked a not-locked lock at 0x........ (7) no error on next line (8) ERROR on next line -Thread #x unlocked a not-locked lock at 0x........ +Thread #x unlocked a not-locked lock at 0x........ at 0x........: pthread_rwlock_unlock (hg_intercepts.c:...) by 0x........: main (tc20_verifywrap.c:212) Lock at 0x........ was first observed diff --git a/helgrind/tests/tc20_verifywrap.stderr.exp-glibc27-amd64 b/helgrind/tests/tc20_verifywrap.stderr.exp-glibc27-amd64 index 6e9af75d21..997e877a48 100644 --- a/helgrind/tests/tc20_verifywrap.stderr.exp-glibc27-amd64 +++ b/helgrind/tests/tc20_verifywrap.stderr.exp-glibc27-amd64 @@ -58,7 +58,7 @@ Thread #x's call to pthread_mutex_timedlock failed at 0x........: pthread_mutex_timedlock (hg_intercepts.c:...) by 0x........: main (tc20_verifywrap.c:121) -Thread #x unlocked an invalid lock at 0x........ +Thread #x unlocked an invalid lock at 0x........ at 0x........: pthread_mutex_unlock (hg_intercepts.c:...) by 0x........: main (tc20_verifywrap.c:125) @@ -97,7 +97,7 @@ Thread #x's call to pthread_cond_timedwait failed ---------------- pthread_rwlock_* ---------------- -Thread #x unlocked a not-locked lock at 0x........ +Thread #x unlocked a not-locked lock at 0x........ at 0x........: pthread_rwlock_unlock (hg_intercepts.c:...) by 0x........: main (tc20_verifywrap.c:179) Lock at 0x........ was first observed @@ -107,7 +107,7 @@ Thread #x unlocked a not-locked lock at 0x........ (2) no error on next line (3) ERROR on next line -Thread #x unlocked a not-locked lock at 0x........ +Thread #x unlocked a not-locked lock at 0x........ at 0x........: pthread_rwlock_unlock (hg_intercepts.c:...) by 0x........: main (tc20_verifywrap.c:196) Lock at 0x........ was first observed @@ -119,7 +119,7 @@ Thread #x unlocked a not-locked lock at 0x........ (7) no error on next line (8) ERROR on next line -Thread #x unlocked a not-locked lock at 0x........ +Thread #x unlocked a not-locked lock at 0x........ at 0x........: pthread_rwlock_unlock (hg_intercepts.c:...) by 0x........: main (tc20_verifywrap.c:212) Lock at 0x........ was first observed