From patchwork Fri Apr 17 21:31:17 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Roland McGrath X-Patchwork-Id: 6314 Received: (qmail 83282 invoked by alias); 17 Apr 2015 21:31:21 -0000 Mailing-List: contact libc-alpha-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: libc-alpha-owner@sourceware.org Delivered-To: mailing list libc-alpha@sourceware.org Received: (qmail 83272 invoked by uid 89); 17 Apr 2015 21:31:21 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-1.7 required=5.0 tests=AWL, BAYES_00, KAM_LAZY_DOMAIN_SECURITY autolearn=no version=3.3.2 X-HELO: topped-with-meat.com MIME-Version: 1.0 From: Roland McGrath To: Cc: Subject: Re: Build problem with ToT GCC In-Reply-To: Steve Ellcey's message of Friday, 17 April 2015 13:46:14 -0700 <1429303574.30498.247.camel@ubuntu-sellcey> References: <88baa580-c27b-4fc8-b7da-7de3c0a7f64d@BAMAIL02.ba.imgtec.org> <20150417192032.70DE42C3B91@topped-with-meat.com> <1429300312.30498.241.camel@ubuntu-sellcey> <20150417195820.664E52C3B86@topped-with-meat.com> <1429300926.30498.243.camel@ubuntu-sellcey> <1429303574.30498.247.camel@ubuntu-sellcey> Message-Id: <20150417213118.08ECE2C3B3B@topped-with-meat.com> Date: Fri, 17 Apr 2015 14:31:17 -0700 (PDT) X-CMAE-Score: 0 X-CMAE-Analysis: v=2.1 cv=SvUDtp+0 c=1 sm=1 tr=0 a=WkljmVdYkabdwxfqvArNOQ==:117 a=14OXPxybAAAA:8 a=kj9zAlcOel0A:10 a=hOe2yjtxAAAA:8 a=iUeFtCjLbuNjL0NKjIkA:9 a=CjuIK1q_8ugA:10 > Weird, I assumed that the dl-close.c issue was the same as the dl-open.c > problem. But it looks different. After cutting it down with delta I > get the following small test case and error. I do not see how GCC can > know that nsid is not 0. It's because of the call to a noreturn function ("bad"): > struct link_namespaces *ns = &_dl_ns[nsid]; > (nsid != 0) ? (void) (0) : bad ("nsid != 0"); > --ns->_ns_nloaded; If 'nsid != 0' is not true, then you never reach the last line, which is the only one actually dereferencing _dl_ns[nsid]. It's rather confusing that it only reports the error at the site of the address calculation and does not show the site of the dereference, let alone the site of the preceding code path that made the compiler believe the value of 'nsid' was constrained (which is a handful of lines earlier: 'assert (nsid != LM_ID_BASE)'). In your minimized example is easy enough to see the relationship. But in the original code, 'ns = &_dl_ns[nsid]' appears over 500 lines before '--ns->_ns_nloaded', which itself is several lines after the assert. The message "subscript is outside" is also somewhat misleading for this case, because the assert that testifies the value cannot be zero is only in one branch of an if test--in the other branch, there is no such assert and so the cited dereference might be just fine (which is the case here, as it's dynamically impossible for the if test to fail, for reasons nobody would expect the compiler to figure out). The ideal message would be something like "subscript is outside array bounds in some code paths" followed by a "note: code paths passing through here" for the line with the assert. You should file a GCC bug about improving the diagnostics for this case. Please try this patch (branch roland/dl-nns): * elf/dl-close.c (_dl_close_worker) [DL_NNS == 1]: Just assert that IMAP->l_prev cannot be null, and #if out the code for the contrary case, avoiding 'assert (nsid != LM_ID_BASE)' making the compiler believe that NS (&_dl_ns[NSID]) could point outside the array. Thanks, Roland diff --git a/elf/dl-close.c b/elf/dl-close.c index cf8f9e0..412f71d 100644 --- a/elf/dl-close.c +++ b/elf/dl-close.c @@ -641,9 +641,16 @@ _dl_close_worker (struct link_map *map) DL_UNMAP (imap); /* Finally, unlink the data structure and free it. */ - if (imap->l_prev != NULL) - imap->l_prev->l_next = imap->l_next; - else +#if DL_NNS == 1 + /* The assert in the (imap->l_prev == NULL) case gives + the compiler license to warn that NS points outside + the dl_ns array bounds in that case (as nsid != LM_ID_BASE + is tantamount to nsid >= DL_NNS). That should be impossible + in this configuration, so just assert about it instead. */ + assert (nsid == LM_ID_BASE); + assert (imap->l_prev != NULL); +#else + if (imap->l_prev == NULL) { assert (nsid != LM_ID_BASE); ns->_ns_loaded = imap->l_next; @@ -652,6 +659,9 @@ _dl_close_worker (struct link_map *map) we leave for debuggers to examine. */ r->r_map = (void *) ns->_ns_loaded; } + else +#endif + imap->l_prev->l_next = imap->l_next; --ns->_ns_nloaded; if (imap->l_next != NULL)