[Commits] Rev 4516: MDEV-6582: DEBUG_SYNC does not reset mysys_var->current_mutex, causes assertion "Trying to unlock mutex that wasn't locked" in http://bazaar.launchpad.net/~maria-captains/maria/10.0

knielsen at knielsen-hq.org knielsen at knielsen-hq.org
Wed Nov 26 12:07:32 EET 2014


At http://bazaar.launchpad.net/~maria-captains/maria/10.0

------------------------------------------------------------
revno: 4516
revision-id: knielsen at knielsen-hq.org-20141126100732-h1s6prhpj1pem6tu
parent: knielsen at knielsen-hq.org-20141125131911-poi0zfc8ms5tcnkj
committer: Kristian Nielsen <knielsen at knielsen-hq.org>
branch nick: work-10.0
timestamp: Wed 2014-11-26 11:07:32 +0100
message:
  MDEV-6582: DEBUG_SYNC does not reset mysys_var->current_mutex, causes assertion "Trying to unlock mutex that wasn't locked"
  
  The bug was in DEBUG_SYNC. When waiting, debug_sync_execute() temporarily sets
  thd->mysys_var->current_mutex to a new value while waiting. However, if the
  old value of current_mutex was NULL, it was not restored, current_mutex
  remained set to the temporary value (debug_sync_global.ds_mutex).
  
  This made possible the following race: Thread T1 goes to KILL thread T2. In
  THD::awake(), T1 loads T2->mysys_var->current_mutex, it is set to ds_mutex, T1
  locks this mutex.
  
  Now T2 runs, it does ENTER_COND, it sets T2->mysys_var->current_mutex to
  LOCK_wait_commit (for example).
  
  Then T1 resumes, it reloads mysys_var->current_mutex, now it is set to
  LOCK_wait_commit, T1 unlocks this mutex instead of the ds_mutex that it locked
  previously.
  
  This causes safe_mutex to assert with the message: "Trying to unlock mutex
  LOCK_wait_commit that wasn't locked".
  
  The fix is to ensure that DEBUG_SYNC also will restore
  mysys_var->current_mutex in the case where the original value was NULL.
=== modified file 'sql/debug_sync.cc'
--- a/sql/debug_sync.cc	2014-09-30 17:31:14 +0000
+++ b/sql/debug_sync.cc	2014-11-26 10:07:32 +0000
@@ -1394,8 +1394,9 @@ static void debug_sync_execute(THD *thd,
 
     if (action->wait_for.length())
     {
-      mysql_mutex_t *old_mutex;
+      mysql_mutex_t *old_mutex= NULL;
       mysql_cond_t  *old_cond= NULL;
+      bool           restore_current_mutex;
       int             error= 0;
       struct timespec abstime;
 
@@ -1412,11 +1413,12 @@ static void debug_sync_execute(THD *thd,
       {
         old_mutex= thd->mysys_var->current_mutex;
         old_cond= thd->mysys_var->current_cond;
+        restore_current_mutex = true;
         thd->mysys_var->current_mutex= &debug_sync_global.ds_mutex;
         thd->mysys_var->current_cond= &debug_sync_global.ds_cond;
       }
       else
-        old_mutex= NULL;
+        restore_current_mutex = false;
 
       set_timespec(abstime, action->timeout);
       DBUG_EXECUTE("debug_sync_exec", {
@@ -1476,7 +1478,7 @@ static void debug_sync_execute(THD *thd,
         is locked. (See comment in THD::exit_cond().)
       */
       mysql_mutex_unlock(&debug_sync_global.ds_mutex);
-      if (old_mutex)
+      if (restore_current_mutex)
       {
         mysql_mutex_lock(&thd->mysys_var->mutex);
         thd->mysys_var->current_mutex= old_mutex;



More information about the commits mailing list