The dladdr() function is supposed to return 0 if no shared library was
found containing the given address, and we neglected to do this and always
returned 1. So this patch fixes the return value of dladdr() to match the
Linux one, and return 0 when it needs to.

One consequence of this bug was that PR_GetLibraryFilePathname() from the
nspr4 library assumed that when dladdr() returned 1, it also returned a
non-null filename, and it could strlen() it. Our wrong return value broke
this assumption.

This patch also fixes the underlying OSv-specific method object::lookup_addr()
to set the returned fname and base to the object's values when the address
belongs to this object - even if not to any known symbol, because we need
this behavior in dladdr().

Fixes #878, but openjdk8-fedora+tomcat still does not work, because
of yet another bug.

Signed-off-by: Nadav Har'El <[email protected]>
---
 core/elf.cc   | 4 ++--
 libc/dlfcn.cc | 7 +++++--
 2 files changed, 7 insertions(+), 4 deletions(-)

diff --git a/core/elf.cc b/core/elf.cc
index 8eab695..2a413a4 100644
--- a/core/elf.cc
+++ b/core/elf.cc
@@ -827,6 +827,8 @@ dladdr_info object::lookup_addr(const void* addr)
     if (addr < _base || addr >= _end) {
         return ret;
     }
+    ret.fname = _pathname.c_str();
+    ret.base = _base;
     auto strtab = dynamic_ptr<char>(DT_STRTAB);
     auto symtab = dynamic_ptr<Elf64_Sym>(DT_SYMTAB);
     auto len = symtab_len();
@@ -853,8 +855,6 @@ dladdr_info object::lookup_addr(const void* addr)
     if (!best.symbol || addr > best.relocated_addr() + best.size()) {
         return ret;
     }
-    ret.fname = _pathname.c_str();
-    ret.base = _base;
     ret.sym = strtab + best.symbol->st_name;
     ret.addr = best.relocated_addr();
     return ret;
diff --git a/libc/dlfcn.cc b/libc/dlfcn.cc
index 2c28075..ba6bcce 100644
--- a/libc/dlfcn.cc
+++ b/libc/dlfcn.cc
@@ -123,8 +123,11 @@ extern "C" int dladdr(void *addr, Dl_info *info)
     info->dli_fbase = ei.base;
     info->dli_sname = ei.sym;
     info->dli_saddr = ei.addr;
-    /* dladdr returns non-zero on success and 0 on error */
-    return 1;
+    // dladdr() should return 0 only when the address is not contained in a
+    // shared object. It should return 1 when we were able to find the object
+    // (dli_fname, dli_fbase) even if we couldn't find the specific symbol
+    // (dli_sname, dli_saddr).
+    return ei.base ? 1 : 0;
 }
 
 extern "C" char *dlerror(void)
-- 
2.9.4

-- 
You received this message because you are subscribed to the Google Groups "OSv 
Development" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
For more options, visit https://groups.google.com/d/optout.

Reply via email to