summaryrefslogtreecommitdiff
path: root/ldso/dynlink.c
diff options
context:
space:
mode:
authorRich Felker <dalias@aerifal.cx>2018-06-28 11:51:43 -0400
committerRich Felker <dalias@aerifal.cx>2018-06-28 12:05:23 -0400
commitc8b49b2fbc7faa8bf065220f11963d76c8a2eb93 (patch)
tree025af00a9ee6e135c58733602f594616c3e807bc /ldso/dynlink.c
parent8b8fb7f03721c42445f982582f462144ab60a1a0 (diff)
downloadmusl-c8b49b2fbc7faa8bf065220f11963d76c8a2eb93.tar.gz
fix symtab-order-dependent spurious matches in dladdr
commit 8b8fb7f03721c42445f982582f462144ab60a1a0 added logic to prevent matching a symbol with no recorded size (closest-match) when there is an intervening symbol whose size was recorded, but it only worked when the intervening symbol was encountered later in the search. instead of rejecting symbols where addr falls outside their recorded size during the closest-match search, accept them to find the true closest-match, then reject such a result only once the search has finished.
Diffstat (limited to 'ldso/dynlink.c')
-rw-r--r--ldso/dynlink.c13
1 files changed, 8 insertions, 5 deletions
diff --git a/ldso/dynlink.c b/ldso/dynlink.c
index 31c50609..d963aeab 100644
--- a/ldso/dynlink.c
+++ b/ldso/dynlink.c
@@ -1951,6 +1951,7 @@ int dladdr(const void *addr_arg, Dl_info *info)
uint32_t nsym;
char *strings;
size_t best = 0;
+ size_t besterr = -1;
pthread_rwlock_rdlock(&lock);
p = addr2dso(addr);
@@ -1968,6 +1969,7 @@ int dladdr(const void *addr_arg, Dl_info *info)
if (idx < nsym && (sym[idx].st_info&0xf) == STT_FUNC) {
best = (size_t)(p->funcdescs + idx);
bestsym = sym + idx;
+ besterr = 0;
}
}
@@ -1978,18 +1980,19 @@ int dladdr(const void *addr_arg, Dl_info *info)
size_t symaddr = (size_t)laddr(p, sym->st_value);
if (symaddr > addr || symaddr < best)
continue;
- if (sym->st_size && symaddr+sym->st_size <= addr) {
- best = 0;
- bestsym = 0;
- continue;
- }
best = symaddr;
bestsym = sym;
+ besterr = addr - symaddr;
if (addr == symaddr)
break;
}
}
+ if (bestsym && besterr > bestsym->st_size-1) {
+ best = 0;
+ bestsym = 0;
+ }
+
info->dli_fname = p->name;
info->dli_fbase = p->map;