Author: sewardj
Date: 2007-11-05 02:11:57 +0000 (Mon, 05 Nov 2007)
New Revision: 7091

Log:
Add machinery to check for bogus mutex arguments to pthread_cond_wait,
since the documentation claims that functionality is provided :-)

Modified:
   branches/THRCHECK/thrcheck/tc_intercepts.c
   branches/THRCHECK/thrcheck/tc_main.c


Modified: branches/THRCHECK/thrcheck/tc_intercepts.c
===================================================================
--- branches/THRCHECK/thrcheck/tc_intercepts.c  2007-11-05 02:10:33 UTC (rev 
7090)
+++ branches/THRCHECK/thrcheck/tc_intercepts.c  2007-11-05 02:11:57 UTC (rev 
7091)
@@ -86,6 +86,19 @@
                                  _arg1,_arg2,0,0,0);     \
    } while (0)
 
+#define DO_CREQ_W_WW(_resF, _creqF, _ty1F,_arg1F, _ty2F,_arg2F)        \
+   do {                                                  \
+      Word _res, _arg1, _arg2;                           \
+      assert(sizeof(_ty1F) == sizeof(Word));             \
+      assert(sizeof(_ty2F) == sizeof(Word));             \
+      _arg1 = (Word)(_arg1F);                            \
+      _arg2 = (Word)(_arg2F);                            \
+      VALGRIND_DO_CLIENT_REQUEST(_res, 2,                \
+                                 (_creqF),               \
+                                 _arg1,_arg2,0,0,0);     \
+      _resF = _res;                                      \
+   } while (0)
+
 #define DO_CREQ_v_WWW(_creqF, _ty1F,_arg1F,              \
                      _ty2F,_arg2F, _ty3F, _arg3F)       \
    do {                                                  \
@@ -525,6 +538,8 @@
 {
    int ret;
    OrigFn fn;
+   unsigned long mutex_is_valid;
+
    VALGRIND_GET_ORIG_FN(fn);
 
    if (TRACE_PTH_FNS) {
@@ -532,26 +547,39 @@
       fflush(stderr);
    }
 
+   /* Tell the tool a cond-wait is about to happen, so it can check
+      for bogus argument values.  In return it tells us whether it
+      thinks the mutex is valid or not. */
+   DO_CREQ_W_WW(mutex_is_valid,
+                _VG_USERREQ__TC_PTHREAD_COND_WAIT_PRE,
+                pthread_cond_t*,cond, pthread_mutex_t*,mutex);
+   assert(mutex_is_valid == 1 || mutex_is_valid == 0);
+
    /* Tell the tool we're about to drop the mutex.  This reflects the
       fact that in a cond_wait, we show up holding the mutex, and the
       call atomically drops the mutex and waits for the cv to be
       signalled. */
-   DO_CREQ_v_W(_VG_USERREQ__TC_PTHREAD_MUTEX_UNLOCK_PRE,
-               pthread_mutex_t*,mutex);
+   if (mutex_is_valid) {
+      DO_CREQ_v_W(_VG_USERREQ__TC_PTHREAD_MUTEX_UNLOCK_PRE,
+                  pthread_mutex_t*,mutex);
+   }
 
    CALL_FN_W_WW(ret, fn, cond,mutex);
 
-   /* And now we have the mutex again, regardless of the error code
-      returned. */
-   // FIXME: but only if we actually had it before the call
-   DO_CREQ_v_W(_VG_USERREQ__TC_PTHREAD_MUTEX_LOCK_POST,
-               pthread_mutex_t*,mutex);
+   /* these conditionals look stupid, but compare w/ same logic for
+      pthread_cond_timedwait below */
+   if (ret == 0 && mutex_is_valid) {
+      /* and now we have the mutex again */
+      DO_CREQ_v_W(_VG_USERREQ__TC_PTHREAD_MUTEX_LOCK_POST,
+                  pthread_mutex_t*,mutex);
+   }
 
-   if (ret == 0) {
+   if (ret == 0 && mutex_is_valid) {
       DO_CREQ_v_WW(_VG_USERREQ__TC_PTHREAD_COND_WAIT_POST,
                    pthread_cond_t*,cond, pthread_mutex_t*,mutex);
+   }
 
-   } else { 
+   if (ret != 0) {
       DO_PthAPIerror( "pthread_cond_wait", ret );
    }
 
@@ -570,6 +598,7 @@
 {
    int ret;
    OrigFn fn;
+   unsigned long mutex_is_valid;
    VALGRIND_GET_ORIG_FN(fn);
 
    if (TRACE_PTH_FNS) {
@@ -578,29 +607,38 @@
       fflush(stderr);
    }
 
+   /* Tell the tool a cond-wait is about to happen, so it can check
+      for bogus argument values.  In return it tells us whether it
+      thinks the mutex is valid or not. */
+   DO_CREQ_W_WW(mutex_is_valid,
+                _VG_USERREQ__TC_PTHREAD_COND_WAIT_PRE,
+                pthread_cond_t*,cond, pthread_mutex_t*,mutex);
+   assert(mutex_is_valid == 1 || mutex_is_valid == 0);
+
    /* Tell the tool we're about to drop the mutex.  This reflects the
       fact that in a cond_wait, we show up holding the mutex, and the
       call atomically drops the mutex and waits for the cv to be
       signalled. */
-   DO_CREQ_v_W(_VG_USERREQ__TC_PTHREAD_MUTEX_UNLOCK_PRE,
-               pthread_mutex_t*,mutex);
+   if (mutex_is_valid) {
+      DO_CREQ_v_W(_VG_USERREQ__TC_PTHREAD_MUTEX_UNLOCK_PRE,
+                  pthread_mutex_t*,mutex);
+   }
 
    CALL_FN_W_WWW(ret, fn, cond,mutex,abstime);
 
-   /* And now we have the mutex again, regardless of the error code
-      returned.  In particular we still have it even if
-      ret==ETIMEDOUT. */
-   // FIXME: but only if we actually had it before the call
-   DO_CREQ_v_W(_VG_USERREQ__TC_PTHREAD_MUTEX_LOCK_POST,
-               pthread_mutex_t*,mutex);
+   if ((ret == 0 || ret == ETIMEDOUT) && mutex_is_valid) {
+      /* and now we have the mutex again */
+      DO_CREQ_v_W(_VG_USERREQ__TC_PTHREAD_MUTEX_LOCK_POST,
+                  pthread_mutex_t*,mutex);
+   }
 
-   if (ret == 0) {
+   if (ret == 0 && mutex_is_valid) {
       DO_CREQ_v_WW(_VG_USERREQ__TC_PTHREAD_COND_WAIT_POST,
                    pthread_cond_t*,cond, pthread_mutex_t*,mutex);
+   }
 
-   } else {
-      if (ret != ETIMEDOUT)
-         DO_PthAPIerror( "pthread_cond_timedwait", ret );
+   if (ret != 0 && ret != ETIMEDOUT) {
+      DO_PthAPIerror( "pthread_cond_timedwait", ret );
    }
 
    if (TRACE_PTH_FNS) {

Modified: branches/THRCHECK/thrcheck/tc_main.c
===================================================================
--- branches/THRCHECK/thrcheck/tc_main.c        2007-11-05 02:10:33 UTC (rev 
7090)
+++ branches/THRCHECK/thrcheck/tc_main.c        2007-11-05 02:11:57 UTC (rev 
7091)
@@ -5918,7 +5918,7 @@
         && TC_(elemBag)( lk->heldBy, (Word)thr ) > 0 ) {
       /* uh, it's a non-recursive lock and we already w-hold it, and
          this is a real lock operation (not a speculative "tryLock"
-         kind of thing.  Duh.  Deadlock coming up; but at least
+         kind of thing).  Duh.  Deadlock coming up; but at least
          produce an error message. */
       record_error_Misc( thr, "Attempt to re-lock a "
                               "non-recursive lock I already hold" );
@@ -6031,10 +6031,15 @@
    }
 }
 
-static void evh__TC_PTHREAD_COND_WAIT_PRE ( ThreadId tid,
+/* returns True if it reckons 'mutex' is valid and held by this
+   thread, else False */
+static Bool evh__TC_PTHREAD_COND_WAIT_PRE ( ThreadId tid,
                                             void* cond, void* mutex )
 {
    Thread* thr;
+   Lock*   lk;
+   Bool    lk_valid = True;
+
    if (SHOW_EVENTS >= 1)
       VG_(printf)("evh__tc_PTHREAD_COND_WAIT_PRE"
                   "(ctid=%d, cond=%p, mutex=%p)\n", 
@@ -6044,7 +6049,41 @@
    thr = map_threads_maybe_lookup( tid );
    tl_assert(thr); /* cannot fail - Thread* must already exist */
 
+   lk = map_locks_maybe_lookup( (Addr)mutex );
+
+   /* Check for stupid mutex arguments.  There are various ways to be
+      a bozo.  Only complain once, though, even if more than one thing
+      is wrong. */
+   if (lk == NULL) {
+      lk_valid = False;
+      record_error_Misc( 
+         thr, 
+         "pthread_cond_wait called with invalid mutex" );
+   } else {
+      tl_assert( is_sane_LockN(lk) );
+      if (lk->kind == LK_rdwr) {
+         lk_valid = False;
+         record_error_Misc( 
+            thr, "pthread_cond_wait called with mutex "
+                 "of type pthread_rwlock_t*" );
+      } else
+         if (lk->heldBy == NULL) {
+         lk_valid = False;
+         record_error_Misc( 
+            thr, "pthread_cond_wait called with un-held mutex");
+      } else
+      if (lk->heldBy != NULL
+          && TC_(elemBag)( lk->heldBy, (Word)thr ) == 0) {
+         lk_valid = False;
+         record_error_Misc( 
+            thr, "pthread_cond_wait called with mutex "
+                 "held by a different thread" );
+      }
+   }
+
    // error-if: cond is also associated with a different mutex
+
+   return lk_valid;
 }
 
 static void evh__TC_PTHREAD_COND_WAIT_POST ( ThreadId tid,
@@ -7477,17 +7516,22 @@
          evh__TC_PTHREAD_COND_SIGNAL_PRE( tid, (void*)args[1] );
          break;
 
-      /* Entry into pthread_cond_wait, cond=arg[1], mutex=arg[2] */
-      case _VG_USERREQ__TC_PTHREAD_COND_WAIT_PRE:
-         evh__TC_PTHREAD_COND_WAIT_PRE( tid,
-                                         (void*)args[1], (void*)args[2] );
+      /* Entry into pthread_cond_wait, cond=arg[1], mutex=arg[2].
+         Returns a flag indicating whether or not the mutex is believed to be
+         valid for this operation. */
+      case _VG_USERREQ__TC_PTHREAD_COND_WAIT_PRE: {
+         Bool mutex_is_valid
+            = evh__TC_PTHREAD_COND_WAIT_PRE( tid, (void*)args[1], 
+                                                  (void*)args[2] );
+         *ret = mutex_is_valid ? 1 : 0;
          break;
+      }
 
       /* Thread successfully completed pthread_cond_wait, cond=arg[1],
          mutex=arg[2] */
       case _VG_USERREQ__TC_PTHREAD_COND_WAIT_POST:
          evh__TC_PTHREAD_COND_WAIT_POST( tid,
-                                          (void*)args[1], (void*)args[2] );
+                                         (void*)args[1], (void*)args[2] );
          break;
 
       case _VG_USERREQ__TC_PTHREAD_RWLOCK_INIT_POST:
@@ -8371,7 +8415,7 @@
       clo_happens_before = 0;
    else if (VG_CLO_STREQ(arg, "--happens-before=threads"))
       clo_happens_before = 1;
-   else if (VG_CLO_STREQ(arg, "--happens-before=condvars"))
+   else if (VG_CLO_STREQ(arg, "--happens-before=all"))
       clo_happens_before = 2;
 
    else if (VG_CLO_STREQ(arg, "--gen-vcg=no"))
@@ -8424,8 +8468,8 @@
 static void tc_print_usage ( void )
 {
    VG_(printf)(
-"    --happens-before=none|threads|condvars   [condvars] consider no events,\n"
-"      thread create/join, thread create/join/cvsignal/cvwait as sync points\n"
+"    --happens-before=none|threads|all   [all] consider no events, thread\n"
+"      create/join, create/join/cvsignal/cvwait/semwait/post as sync points\n"
 "    --trace-addr=0xXXYYZZ     show all state changes for address 0xXXYYZZ\n"
 "    --trace-level=0|1|2       verbosity level of --trace-addr [1]\n"
    );


-------------------------------------------------------------------------
This SF.net email is sponsored by: Splunk Inc.
Still grepping through log files to find problems?  Stop.
Now Search log events and configuration files using AJAX and a browser.
Download your FREE copy of Splunk now >> http://get.splunk.com/
_______________________________________________
Valgrind-developers mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/valgrind-developers

Reply via email to