This is the mail archive of the
libc-alpha@sourceware.org
mailing list for the glibc project.
Re: Build problem with ToT GCC
- From: Roland McGrath <roland at hack dot frob dot com>
- To: <sellcey at imgtec dot com>
- Cc: <libc-alpha at sourceware dot org>
- Date: Fri, 17 Apr 2015 14:31:17 -0700 (PDT)
- Subject: Re: Build problem with ToT GCC
- Authentication-results: sourceware.org; auth=none
- References: <88baa580-c27b-4fc8-b7da-7de3c0a7f64d at BAMAIL02 dot ba dot imgtec dot org> <20150417192032 dot 70DE42C3B91 at topped-with-meat dot com> <1429300312 dot 30498 dot 241 dot camel at ubuntu-sellcey> <20150417195820 dot 664E52C3B86 at topped-with-meat dot com> <1429300926 dot 30498 dot 243 dot camel at ubuntu-sellcey> <1429303574 dot 30498 dot 247 dot camel at ubuntu-sellcey>
> 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.
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)
Thanks,
Roland