diff options
author | Kristian Nielsen <knielsen@knielsen-hq.org> | 2014-11-26 11:07:32 +0100 |
---|---|---|
committer | Kristian Nielsen <knielsen@knielsen-hq.org> | 2014-11-26 11:07:32 +0100 |
commit | 06d0d090770571f8cd290d075f8195a7e8d18d7c (patch) | |
tree | ef43d8ee5b21d6baecd2d9e85790ff6c817e18d2 | |
parent | e79b7ca966040d5da910e823e98841efd7c3556b (diff) | |
download | mariadb-git-06d0d090770571f8cd290d075f8195a7e8d18d7c.tar.gz |
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.
-rw-r--r-- | sql/debug_sync.cc | 8 |
1 files changed, 5 insertions, 3 deletions
diff --git a/sql/debug_sync.cc b/sql/debug_sync.cc index 2980ecd7dbf..5802d726aa2 100644 --- a/sql/debug_sync.cc +++ b/sql/debug_sync.cc @@ -1394,8 +1394,9 @@ static void debug_sync_execute(THD *thd, st_debug_sync_action *action) 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, st_debug_sync_action *action) { 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, st_debug_sync_action *action) 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; |