diff --git a/Misc/NEWS.d/next/Core and Builtins/2019-09-12-16-36-16.bpo-38106.4pApn7.rst b/Misc/NEWS.d/next/Core and Builtins/2019-09-12-16-36-16.bpo-38106.4pApn7.rst new file mode 100644 index 00000000000..b2b80ceece8 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2019-09-12-16-36-16.bpo-38106.4pApn7.rst @@ -0,0 +1,5 @@ +Fix race in PyThread_release_lock that was leading to memory corruption and +deadlocks. The fix applies to POSIX systems where Python locks are implemented +with mutex and condition variable because POSIX semaphores are either not +provided, or are known to be broken. One particular example of such system is +macOS. diff --git a/Python/thread_pthread.h b/Python/thread_pthread.h index 6d4b3b389f8..4d792a123a7 100644 --- a/Python/thread_pthread.h +++ b/Python/thread_pthread.h @@ -430,12 +430,15 @@ PyThread_free_lock(PyThread_type_lock lock) (void) error; /* silence unused-but-set-variable warning */ dprintf(("PyThread_free_lock(%p) called\n", lock)); - status = pthread_mutex_destroy( &thelock->mut ); - CHECK_STATUS("pthread_mutex_destroy"); - + /* some pthread-like implementations tie the mutex to the cond + * and must have the cond destroyed first. + */ status = pthread_cond_destroy( &thelock->lock_released ); CHECK_STATUS("pthread_cond_destroy"); + status = pthread_mutex_destroy( &thelock->mut ); + CHECK_STATUS("pthread_mutex_destroy"); + free((void *)thelock); } @@ -497,12 +500,12 @@ PyThread_release_lock(PyThread_type_lock lock) thelock->locked = 0; - status = pthread_mutex_unlock( &thelock->mut ); - CHECK_STATUS("pthread_mutex_unlock[3]"); - /* wake up someone (anyone, if any) waiting on the lock */ status = pthread_cond_signal( &thelock->lock_released ); CHECK_STATUS("pthread_cond_signal"); + + status = pthread_mutex_unlock( &thelock->mut ); + CHECK_STATUS("pthread_mutex_unlock[3]"); } #endif /* USE_SEMAPHORES */