From: Nadav Har'El <n...@scylladb.com>
Committer: Nadav Har'El <n...@scylladb.com>
Branch: master

Fix dladdr() return value

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 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 <n...@scylladb.com>
Message-Id: <20170608115157.5552-1-...@scylladb.com>

---
diff --git a/core/elf.cc b/core/elf.cc
--- 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
--- 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)

--
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 osv-dev+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to