Skip to content

Commit 06f6e00

Browse files
committed
Bug#21966621: USAGE OF AUTO_RW_LOCK_READ/WRITE ON ALREADY LOCKED OBJECT CAUSES DEADLOCK
Fault description: There is an internal fault in pthread that causes a deadlock when mysql_rwlock_rdlock, mysql_rwlock_unlock functions are used in wrong way. The faulty was triggered by calling two time lock function on already locked object, following seqence: pthread_rwlock_t *x; ... pthread_rwlock_wrlock(x); // R:0 pthread_rwlock_wrlock(x); // R:EDEADLK pthread_rwlock_unlock(x); pthread_rwlock_unlock(x); // Fault - pthread function doesn't check if the x object is still lock, it always decrement the lock-counter which causes an underflow pthread_rwlock_wrlock(x); // Deadlock - lock counter != 0 The production code wasn't checking the result returned by locking function (EDEADLK, EINVAL) and it still was relasing mutex two times (RAII - destructor in object). Incorrect behaviour: The fault occured when pluging doesn't release the srv_session and leaves it to be released be server. When server is releasing the session its using Mutexed_map_thd_srv_session class to opearte on session list. Each method of this class is guarded by rwlock, thus function close_all_sessions_of_plugin_if_any() was calling Mutexed_map_thd_srv_session::do_for_all_matching (locking the mutex) and the callback was removing the session from the list by Mutexed_map_thd_srv_session::remove(second lock). Last call leaves the mutex in invalid state thus next attempt of accesing it will cause a deadlock. Fix description: The solution checks in constructor of Auto_rw_lock_read,Auto_rw_lock_write the result code mysql_rwlock_rdlock and if it wasn't locked then corresponding release function in destructor isn't called. The locking result could be also checked with assert to tell alert that the code is working wrongly. Reviewed-by: [email protected] RB: 10561
1 parent e95e3e8 commit 06f6e00

File tree

3 files changed

+29
-6
lines changed

3 files changed

+29
-6
lines changed

mysql-test/suite/test_service_sql_api/r/test_x_sessions_deinit.result

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,19 @@ srv_session_open 1 - Success
2424
srv_session_close 1 - Success
2525
srv_session_close 1 - Failed
2626
deinit thread
27+
Follows threaded run and leaves open session (Bug#21966621)
28+
========================================================================
29+
init thread
30+
nb_sessions = 1
31+
srv_session_open 1 - Success
32+
deinit thread
33+
========================================================================
34+
init thread
35+
nb_sessions = 1
36+
srv_session_open 1 - Success
37+
srv_session_close 1 - Success
38+
srv_session_close 1 - Failed
39+
deinit thread
2740
Follows threaded run and leaves open session (Bug#21983102)
2841
========================================================================
2942
init thread

plugin/test_service_sql_api/test_x_sessions_deinit.cc

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -222,6 +222,16 @@ static int test_session_service_plugin_deinit(void *p)
222222
WRITE_STR("Follows threaded run\n");
223223
test_in_spawned_thread(p, test_session);
224224

225+
WRITE_STR("Follows threaded run and leaves open session (Bug#21966621)\n");
226+
// Bug#21966621 - Leave session open at srv thread exit which is doing the release in following way:
227+
// 1) Lock LOCK_collection while doing release callback for every session
228+
// 2) Second attempt of LOCK_collection fails while removing session by the callback.
229+
// While exiting both function LOCK_collection is left in invalid state because
230+
// it was released 2 times, lock 1 time
231+
// 3) at next attempt of LOCK_collection usage causes deadlock
232+
test_in_spawned_thread(p, test_session_open); // step 1, 2
233+
test_in_spawned_thread(p, test_session); // step 3
234+
225235
WRITE_STR("Follows threaded run and leaves open session (Bug#21983102)\n");
226236
// Bug#21983102 - iterates through sessions list in which elements are removed
227237
// thus the iterator becomes invalid causing random crashes and

sql/srv_session.cc

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -58,10 +58,10 @@ static bool srv_session_THRs_initialized= false;
5858
class Auto_rw_lock_read
5959
{
6060
public:
61-
explicit Auto_rw_lock_read(mysql_rwlock_t *lock) : rw_lock(lock)
61+
explicit Auto_rw_lock_read(mysql_rwlock_t *lock) : rw_lock(NULL)
6262
{
63-
if (rw_lock)
64-
mysql_rwlock_rdlock(rw_lock);
63+
if (lock && 0 == mysql_rwlock_rdlock(lock))
64+
rw_lock = lock;
6565
}
6666

6767
~Auto_rw_lock_read()
@@ -80,10 +80,10 @@ class Auto_rw_lock_read
8080
class Auto_rw_lock_write
8181
{
8282
public:
83-
explicit Auto_rw_lock_write(mysql_rwlock_t *lock) : rw_lock(lock)
83+
explicit Auto_rw_lock_write(mysql_rwlock_t *lock) : rw_lock(NULL)
8484
{
85-
if (rw_lock)
86-
mysql_rwlock_wrlock(rw_lock);
85+
if (lock && 0 == mysql_rwlock_wrlock(lock))
86+
rw_lock = lock;
8787
}
8888

8989
~Auto_rw_lock_write()

0 commit comments

Comments
 (0)