Re: Thread-unsafe access to lock->owner in PR_Lock
Wan-Teh Chang <[email protected]> Thu, 19 Dec 2013 15:47:42 -0800
| Newsgroups | gmane.comp.mozilla.devel.nspr |
|---|---|
| Message-ID | <CALTJjxHYJFj3SZNSBpbjJxYBhyC=Tc0+PssFTvN6Fs41OzQ4rw@mail.gmail.com> |
On Wed, Dec 18, 2013 at 3:46 AM, Alexander Potapenko <[email protected]> wrote: > Hi NSPR developers, > > while running Chromium tests under ThreadSanitizer (https://code.google.com/p/data-race-test/) we've encountered a report about a data race between PR_Lock and PR_Unlock: http://crbug.com/328521 > > It turns out that the lock->owner variable is being read by PR_Lock at the same time other threads read or write it in PR_Lock or PR_Unlock: > > 189 PR_IMPLEMENT(void) PR_Lock(PRLock *lock) > 190 { > 191 PRThread *me = _PR_MD_CURRENT_THREAD(); > 192 PRIntn is; > 193 PRThread *t; > 194 PRCList *q; > 195 > 196 PR_ASSERT(me != suspendAllThread); > 197 PR_ASSERT(!(me->flags & _PR_IDLE_THREAD)); > 198 PR_ASSERT(lock != NULL); > 199 #ifdef _PR_GLOBAL_THREADS_ONLY > 200 PR_ASSERT(lock->owner != me); > 201 _PR_MD_LOCK(&lock->ilock); > 202 lock->owner = me; > 203 return; > 204 #else /* _PR_GLOBAL_THREADS_ONLY */ > > (code from nspr-4.9.5/mozilla/nsprpub/pr/src/threads/combined/prulock.c in Ubuntu Precise) > [...] > > Is there a reason to do this check before the lock is taken? I'm guessing > it's there to avoid reentrancy, so it should be fine to swap lines 200 and 201. Hi Alexander, PRLock is a non-recursive lock. So the PR_ASSERT(lock->owner != me) on line 200 is trying to detect an attempt to lock a PRLock recursively. It is intended as a debugging aid for NSPR users. This debugging aid is useful, so ideally we should find a way to do it the right way. If we swap lines 200 and 201, it will only work for a _PR_MD_LOCK implementation that allows a lock to be acquired recursively. As Dave Hylands pointed out, in a _PR_MD_LOCK implementation that deadlocks, we won't be able to see the assertion failure. However, since we only use the PR_Lock code in prulock.c on Windows, where _PR_MD_LOCK (EnterCriticalSection) is recursive, we can make the change you suggested. I checked the other PR_Lock implementation in ptsynch.c: http://mxr.mozilla.org/nspr/source/pr/src/pthreads/ptsynch.c#170 It doesn't have the equivalent assertion, and nobody complained, so we can also just remove the assertion. Wan-Teh