summaryrefslogtreecommitdiff
path: root/sql/sql_class.cc
diff options
context:
space:
mode:
authorunknown <knielsen@knielsen-hq.org>2013-11-06 11:29:07 +0100
committerunknown <knielsen@knielsen-hq.org>2013-11-06 11:29:07 +0100
commitc90f4f02124ad0b675b541d7298627506d298ffa (patch)
tree3aa993eddfe11a67244f088b2a44601d97b76e8f /sql/sql_class.cc
parentbdbf90b9693ac089425d125c74078f2c22189454 (diff)
downloadmariadb-git-c90f4f02124ad0b675b541d7298627506d298ffa.tar.gz
MDEV-4506: Parallel replication
MDEV-5217: Unlock of de-allocated mutex There was a race in the code for wait_for_commit::wakeup(). Since the waiter does a dirty read of the waiting_for_commit flag, it was possible for the waiter to complete and deallocate the wait_for_commit object while the waitee was still running inside wakeup(). This would cause the waitee to access invalid memory. Fixed by putting an extra lock/unlock in the destructor for wait_for_commit, to ensure that waitee has finished with the object before it is deallocated.
Diffstat (limited to 'sql/sql_class.cc')
-rw-r--r--sql/sql_class.cc28
1 files changed, 27 insertions, 1 deletions
diff --git a/sql/sql_class.cc b/sql/sql_class.cc
index 09723a1789e..42981e9936c 100644
--- a/sql/sql_class.cc
+++ b/sql/sql_class.cc
@@ -5672,6 +5672,27 @@ wait_for_commit::wait_for_commit()
wait_for_commit::~wait_for_commit()
{
+ /*
+ Since we do a dirty read of the waiting_for_commit flag in
+ wait_for_prior_commit() and in unregister_wait_for_prior_commit(), we need
+ to take extra care before freeing the wait_for_commit object.
+
+ It is possible for the waitee to be pre-empted inside wakeup(), just after
+ it has cleared the waiting_for_commit flag and before it has released the
+ LOCK_wait_commit mutex. And then it is possible for the waiter to find the
+ flag cleared in wait_for_prior_commit() and go finish up things and
+ de-allocate the LOCK_wait_commit and COND_wait_commit objects before the
+ waitee has time to be re-scheduled and finish unlocking the mutex and
+ signalling the condition. This would lead to the waitee accessing no
+ longer valid memory.
+
+ To prevent this, we do an extra lock/unlock of the mutex here before
+ deallocation; this makes certain that any waitee has completed wakeup()
+ first.
+ */
+ mysql_mutex_lock(&LOCK_wait_commit);
+ mysql_mutex_unlock(&LOCK_wait_commit);
+
mysql_mutex_destroy(&LOCK_wait_commit);
mysql_cond_destroy(&COND_wait_commit);
}
@@ -5695,8 +5716,13 @@ wait_for_commit::wakeup(int wakeup_error)
mysql_mutex_lock(&LOCK_wait_commit);
waiting_for_commit= false;
this->wakeup_error= wakeup_error;
- mysql_mutex_unlock(&LOCK_wait_commit);
+ /*
+ Note that it is critical that the mysql_cond_signal() here is done while
+ still holding the mutex. As soon as we release the mutex, the waiter might
+ deallocate the condition object.
+ */
mysql_cond_signal(&COND_wait_commit);
+ mysql_mutex_unlock(&LOCK_wait_commit);
}