From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 13243 invoked by alias); 11 Mar 2011 16:01:31 -0000 Received: (qmail 13144 invoked by uid 22791); 11 Mar 2011 16:01:29 -0000 X-SWARE-Spam-Status: No, hits=-2.8 required=5.0 tests=ALL_TRUSTED,AWL,BAYES_00 X-Spam-Check-By: sourceware.org Received: from localhost (HELO gcc.gnu.org) (127.0.0.1) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Fri, 11 Mar 2011 16:01:25 +0000 From: "eugeni.stepanov at gmail dot com" To: gcc-bugs@gcc.gnu.org Subject: [Bug middle-end/48076] New: Unsafe double checked locking in __emutls_get_address X-Bugzilla-Reason: CC X-Bugzilla-Type: new X-Bugzilla-Watch-Reason: None X-Bugzilla-Product: gcc X-Bugzilla-Component: middle-end X-Bugzilla-Keywords: X-Bugzilla-Severity: normal X-Bugzilla-Who: eugeni.stepanov at gmail dot com X-Bugzilla-Status: UNCONFIRMED X-Bugzilla-Priority: P3 X-Bugzilla-Assigned-To: unassigned at gcc dot gnu.org X-Bugzilla-Target-Milestone: --- X-Bugzilla-Changed-Fields: Message-ID: X-Bugzilla-URL: http://gcc.gnu.org/bugzilla/ Auto-Submitted: auto-generated Content-Type: text/plain; charset="UTF-8" MIME-Version: 1.0 Date: Fri, 11 Mar 2011 16:01:00 -0000 Mailing-List: contact gcc-bugs-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Archive: List-Post: List-Help: Sender: gcc-bugs-owner@gcc.gnu.org X-SW-Source: 2011-03/txt/msg01150.txt.bz2 http://gcc.gnu.org/bugzilla/show_bug.cgi?id=48076 Summary: Unsafe double checked locking in __emutls_get_address Product: gcc Version: 4.4.3 Status: UNCONFIRMED Severity: normal Priority: P3 Component: middle-end AssignedTo: unassigned@gcc.gnu.org ReportedBy: eugeni.stepanov@gmail.com The following piece of code around emutls.c:138 uses double checked locking to initialize a tls offset to the next available value. pointer offset = obj->loc.offset; if (__builtin_expect (offset == 0, 0)) { static __gthread_once_t once = __GTHREAD_ONCE_INIT; __gthread_once (&once, emutls_init); __gthread_mutex_lock (&emutls_mutex); offset = obj->loc.offset; if (offset == 0) { offset = ++emutls_size; obj->loc.offset = offset; } __gthread_mutex_unlock (&emutls_mutex); } struct __emutls_array *arr = __gthread_getspecific (emutls_key); This code needs more barriers to be correct. For example, it is entirely possible for emutls_key value used in the last line of the code snippet to be prefetched before obj->loc.offset is loaded, and, consequently, before emutls_init is called. In short, there needs to be a happens-before relationship between obj->loc.offset assignment and the unprotected read at the first line. This looks unlikely on x86, but it may be a much bigger deal on ARM. This was detected with ThreadSanitizer (http://code.google.com/p/data-race-test/wiki/ThreadSanitizer) on an Android device. ==822== WARNING: Possible data race during read of size 4 at 0x44B74: {{{ ==822== T14 (L{}): ==822== #0 0xB7E0: __emutls_get_address gcc/emutls.c:138 ==822== #1 0x1BFD5: NegativeTests_PerThreadTest::RealWorker() unittest/racecheck_unittest.cc:5665 ==822== #2 0x80107324: ThreadSanitizerStartThread tsan/ts_valgrind_intercepts.c:679 ==822== Concurrent write(s) happened at (OR AFTER) these points: ==822== T12 (L{L312}): ==822== #0 0xB80C: __emutls_get_address gcc/emutls.c:145 ==822== #1 0x1BFD5: NegativeTests_PerThreadTest::RealWorker() unittest/racecheck_unittest.cc:5665 ==822== #2 0x80107324: ThreadSanitizerStartThread tsan/ts_valgrind_intercepts.c:679 ==822== Address 0x44B74 is 8 bytes inside data symbol "__emutls_v._ZN27NegativeTests_PerThreadTestL17per_thread_globalE" ==822== Locks involved in this report (reporting last lock sites): {L312} ==822== L312 (0x44C18) ==822== #0 0x80108084: pthread_mutex_lock tsan/ts_valgrind_intercepts.c:934 ==822== #1 0xB808: __emutls_get_address gcc/gthr-posix.h:768 ==822== #2 0x1BFD5: NegativeTests_PerThreadTest::RealWorker() unittest/racecheck_unittest.cc:5665 ==822== #3 0x80107324: ThreadSanitizerStartThread tsan/ts_valgrind_intercepts.c:679 ==822== Race verifier data: 0xB7E0,0xB80C ==822== }}}