|
From: <sv...@va...> - 2007-11-04 01:51:04
|
Author: sewardj
Date: 2007-11-04 01:51:04 +0000 (Sun, 04 Nov 2007)
New Revision: 7087
Log:
Issue an error message when an exiting thread holds a lock. This is
an obviously unsafe thing to do and is very easy to detect.
Added:
branches/THRCHECK/thrcheck/tests/tc22_exit_w_lock.c
branches/THRCHECK/thrcheck/tests/tc22_exit_w_lock.stderr.exp-glibc25-amd64
branches/THRCHECK/thrcheck/tests/tc22_exit_w_lock.stdout.exp
branches/THRCHECK/thrcheck/tests/tc22_exit_w_lock.vgtest
Modified:
branches/THRCHECK/glibc-2.X-thrcheck.supp
branches/THRCHECK/thrcheck/tc_main.c
branches/THRCHECK/thrcheck/tests/Makefile.am
Modified: branches/THRCHECK/glibc-2.X-thrcheck.supp
===================================================================
--- branches/THRCHECK/glibc-2.X-thrcheck.supp 2007-11-03 23:26:57 UTC (rev 7086)
+++ branches/THRCHECK/glibc-2.X-thrcheck.supp 2007-11-04 01:51:04 UTC (rev 7087)
@@ -68,6 +68,26 @@
fun:*
obj:/lib*/libc-2.5.so
}
+{
+ thrcheck-glibc25-011
+ Thrcheck:Race
+ obj:/lib*/libc-2.5.so
+ obj:/lib*/libpthread-2.5.so
+}
+{
+ thrcheck-glibc25-013
+ Thrcheck:Race
+ obj:/lib*/ld-2.5.so
+ fun:*
+ obj:/lib*/ld-2.5.so
+}
+{
+ thrcheck-glibc25-014
+ Thrcheck:Race
+ obj:/lib*/ld-2.5.so
+ obj:/lib*/ld-2.5.so
+ obj:/lib*/libpthread-2.5.so
+}
# These are very ugly. They are needed to suppress errors inside (eg)
# NPTL's pthread_cond_signal. Why only one stack frame -- at least we
Modified: branches/THRCHECK/thrcheck/tc_main.c
===================================================================
--- branches/THRCHECK/thrcheck/tc_main.c 2007-11-03 23:26:57 UTC (rev 7086)
+++ branches/THRCHECK/thrcheck/tc_main.c 2007-11-04 01:51:04 UTC (rev 7087)
@@ -5515,6 +5515,7 @@
static
void evh__pre_thread_ll_exit ( ThreadId quit_tid )
{
+ Int nHeld;
Thread* thr_q;
if (SHOW_EVENTS >= 1)
VG_(printf)("evh__pre_thread_ll_exit(thr=%d)\n",
@@ -5529,10 +5530,25 @@
finished, and so we need to consider the possibility that it
lingers indefinitely and continues to interact with other
threads. */
+ /* However, it might have rendezvous'd with a thread that called
+ pthread_join with this one as arg, prior to this point (that's
+ how NPTL works). In which case there has already been a prior
+ sync event. So in any case, just let the thread exit. On NPTL,
+ all thread exits go through here. */
tl_assert(is_sane_ThreadId(quit_tid));
thr_q = map_threads_maybe_lookup( quit_tid );
tl_assert(thr_q != NULL);
- // FIXME: error-if: exiting thread holds any locks
+
+ /* Complain if this thread holds any locks. */
+ nHeld = TC_(cardinalityWS)( univ_lsets, thr_q->locksetA );
+ tl_assert(nHeld >= 0);
+ if (nHeld > 0) {
+ HChar buf[80];
+ VG_(sprintf)(buf, "Exiting thread still holds %d lock%s",
+ nHeld, nHeld > 1 ? "s" : "");
+ record_error_Misc( thr_q, buf );
+ }
+
/* About the only thing we do need to do is clear the map_threads
entry, in order that the Valgrind core can re-use it. */
map_threads_delete( quit_tid );
Modified: branches/THRCHECK/thrcheck/tests/Makefile.am
===================================================================
--- branches/THRCHECK/thrcheck/tests/Makefile.am 2007-11-03 23:26:57 UTC (rev 7086)
+++ branches/THRCHECK/thrcheck/tests/Makefile.am 2007-11-04 01:51:04 UTC (rev 7087)
@@ -75,7 +75,9 @@
tc20_verifywrap.stderr.exp-glibc25-x86 \
tc21_pthonce.vgtest tc21_pthonce.stdout.exp \
tc21_pthonce.stderr.exp-glibc25-amd64 \
- tc21_pthonce.stderr.exp-glibc25-x86
+ tc21_pthonce.stderr.exp-glibc25-x86 \
+ tc22_exit_w_lock.vgtest tc22_exit_w_lock.stdout.exp \
+ tc22_exit_w_lock.stderr.exp-glibc25-amd64
check_PROGRAMS = \
hg01_all_ok \
@@ -104,7 +106,8 @@
tc18_semabuse \
tc19_shadowmem \
tc20_verifywrap \
- tc21_pthonce
+ tc21_pthonce \
+ tc22_exit_w_lock
AM_CPPFLAGS = -I$(top_srcdir) -I$(top_srcdir)/include \
-I$(top_srcdir)/coregrind -I$(top_builddir)/include \
Added: branches/THRCHECK/thrcheck/tests/tc22_exit_w_lock.c
===================================================================
--- branches/THRCHECK/thrcheck/tests/tc22_exit_w_lock.c (rev 0)
+++ branches/THRCHECK/thrcheck/tests/tc22_exit_w_lock.c 2007-11-04 01:51:04 UTC (rev 7087)
@@ -0,0 +1,50 @@
+
+#include <pthread.h>
+#include <unistd.h>
+#include <assert.h>
+#include <signal.h>
+
+/* Should see 3 threads exiting in different ways, all holding one (or
+ two) locks. */
+
+pthread_mutex_t mxC1 = PTHREAD_MUTEX_INITIALIZER;
+pthread_mutex_t mxC2 = PTHREAD_MUTEX_INITIALIZER;
+pthread_mutex_t mxC2b = PTHREAD_MUTEX_INITIALIZER;
+pthread_mutex_t mxP = PTHREAD_MUTEX_INITIALIZER;
+
+/* This one exits in the normal way, by joining back */
+void* child_fn1 ( void* arg )
+{
+ int r= pthread_mutex_lock( &mxC1 ); assert(!r);
+ return NULL;
+}
+
+/* This one detaches, does its own thing. */
+void* child_fn2 ( void* arg )
+{
+ int r;
+ r= pthread_mutex_lock( &mxC2 ); assert(!r);
+ r= pthread_mutex_lock( &mxC2b ); assert(!r);
+ r= pthread_detach( pthread_self() ); assert(!r);
+ return NULL;
+}
+
+/* Parent creates 2 children, takes a lock, waits, segfaults. Use
+ sleeps to enforce exit ordering, for repeatable regtesting. */
+int main ( void )
+{
+ int r;
+ pthread_t child1, child2;
+
+ r= pthread_create(&child2, NULL, child_fn2, NULL); assert(!r);
+ sleep(1);
+
+ r= pthread_create(&child1, NULL, child_fn1, NULL); assert(!r);
+ r= pthread_join(child1, NULL); assert(!r);
+ sleep(1);
+
+ r= pthread_mutex_lock( &mxP );
+
+ kill( getpid(), SIGABRT );
+ return 0;
+}
Added: branches/THRCHECK/thrcheck/tests/tc22_exit_w_lock.stderr.exp-glibc25-amd64
===================================================================
--- branches/THRCHECK/thrcheck/tests/tc22_exit_w_lock.stderr.exp-glibc25-amd64 (rev 0)
+++ branches/THRCHECK/thrcheck/tests/tc22_exit_w_lock.stderr.exp-glibc25-amd64 2007-11-04 01:51:04 UTC (rev 7087)
@@ -0,0 +1,30 @@
+
+Thread #2 was created
+ at 0x........: clone (in /...libc...)
+ by 0x........: ...
+ by 0x........: pthread_create@GLIBC_ (in /lib/libpthread...)
+ by 0x........: pthread_create@* (tc_intercepts.c:...)
+ by 0x........: main (tc22_exit_w_lock.c:39)
+
+Thread #2: Exiting thread still holds 2 locks
+ at 0x........: start_thread (in /lib/libpthread...)
+ by 0x........: ...
+
+Thread #3 was created
+ at 0x........: clone (in /...libc...)
+ by 0x........: ...
+ by 0x........: pthread_create@GLIBC_ (in /lib/libpthread...)
+ by 0x........: pthread_create@* (tc_intercepts.c:...)
+ by 0x........: main (tc22_exit_w_lock.c:42)
+
+Thread #3: Exiting thread still holds 1 lock
+ at 0x........: start_thread (in /lib/libpthread...)
+ by 0x........: ...
+
+Thread #1 is the program's root thread
+
+Thread #1: Exiting thread still holds 1 lock
+ at 0x........: kill (in /...libc...)
+ by 0x........: main (tc22_exit_w_lock.c:48)
+
+ERROR SUMMARY: 3 errors from 3 contexts (suppressed: 0 from 0)
Added: branches/THRCHECK/thrcheck/tests/tc22_exit_w_lock.stdout.exp
===================================================================
Added: branches/THRCHECK/thrcheck/tests/tc22_exit_w_lock.vgtest
===================================================================
--- branches/THRCHECK/thrcheck/tests/tc22_exit_w_lock.vgtest (rev 0)
+++ branches/THRCHECK/thrcheck/tests/tc22_exit_w_lock.vgtest 2007-11-04 01:51:04 UTC (rev 7087)
@@ -0,0 +1 @@
+prog: tc22_exit_w_lock
|