Thread-unsafe access to lock->owner in PR_Lock
Alexander Potapenko <[email protected]> Wed, 18 Dec 2013 03:46:30 -0800 (PST)
| Newsgroups | gmane.comp.mozilla.devel.nspr |
|---|---|
| Message-ID | <[email protected]> |
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)
In the case the optimizer is conservative enough nothing will break (during the race lock->owner will be either another thread or NULL, but not |me|), but this is undefined behavior in C++11 and can possibly break in newer compilers.
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.
WBR,
Alexander Potapenko
Software Engineer
Google Moscow