Hi,

As I am sure many are aware, libltdl's error reporting is pretty dumb, lt_dlerror() regularly reports things like "file not found" where the actual problem might be something completely different, and a reasonable error string may be readily available from dlerror().

When I looked at the manual, and read the description for lt_dlerror() I saw "Return a human readable string describing the most recent error that occurred from any of libltdl's functions. Return NULL if no errors have occurred since initialization or since it was last called." and I thought "Well, that's stupid - that's not what dlerror() does". So, I went to see what POSIX says - it's also wrong - http://www.opengroup.org/onlinepubs/9699919799/functions/dlerror.html, I will file a bug with them later.

At least glibc and Mac OS X reset the dlerror() string to NULL every time a dl*() api is called (I will check what other systems do in the next few days). This is so programmers can do:

 .....
 dlsym(handle, "foo");
 if ((err = dlerror()) != NULL) printf(stderr,"dlsym error: %s\n",err);
 ...

without dlerror() returning some other error that occurred long before the call to dlsym().

Unfortunately, it looks like libltdl attempts to save error state across calls to lt_*() functions, and generally does not do it well.

This patch resets the error every time a public ltdl function is called, and when setting an error tests if it is already set and doesn't overwrite it if it is. The fist error "wins".

The patch is fairly simple, and undoubtedly still imperfect, but test results are good, one test required a small patch to stop segfaulting, another should have unexpectedly passed, but doesn't, I think it is another error in the test, but haven't looked too closely yet.

If something like this does get in, I'd prefer to not change the libltld soname, I don't believe better error reporting will cause client applications to break. I could be wrong, of course :)

Patch attached (or course, a final patch will have to change the manual as well) - thoughts?

Peter
diff --git a/libltdl/libltdl/lt__private.h b/libltdl/libltdl/lt__private.h
index f4c4a3d..84f5622 100644
--- a/libltdl/libltdl/lt__private.h
+++ b/libltdl/libltdl/lt__private.h
@@ -138,7 +138,10 @@ struct lt__advise {
 
 #define LT__GETERROR(lvalue)	      (lvalue) = lt__get_last_error()
 #define LT__SETERRORSTR(errormsg)     lt__set_last_error(errormsg)
-#define LT__SETERROR(errorcode)	      LT__SETERRORSTR(LT__STRERROR(errorcode))
+#define LT__SETERROR(errorcode)       if (0 == lt__get_last_error()) \
+					LT__SETERRORSTR(LT__STRERROR(errorcode))
+#define LT__RESETERROR(x)	      lt__set_last_error(0)
+#define LT__FORCEERROR(errorstr)      LT__SETERRORSTR(errorstr)
 
 LT_SCOPE const char *lt__error_string	(int errorcode);
 LT_SCOPE const char *lt__get_last_error	(void);
diff --git a/libltdl/loaders/preopen.c b/libltdl/loaders/preopen.c
index 7149287..58464ca 100644
--- a/libltdl/loaders/preopen.c
+++ b/libltdl/loaders/preopen.c
@@ -293,6 +293,7 @@ int
 lt_dlpreload_default (const lt_dlsymlist *preloaded)
 {
   default_preloaded_symbols = preloaded;
+  LT__RESETERROR ();
   return 0;
 }
 
@@ -303,6 +304,7 @@ int
 lt_dlpreload (const lt_dlsymlist *preloaded)
 {
   int errors = 0;
+  LT__RESETERROR ();
 
   if (preloaded)
     {
@@ -331,6 +333,7 @@ lt_dlpreload_open (const char *originator, lt_dlpreload_callback_func *func)
   symlist_chain *list;
   int		 errors = 0;
   int		 found  = 0;
+  LT__RESETERROR ();
 
   /* For each symlist in the chain...  */
   for (list = preloaded_symlists; list; list = list->next)
diff --git a/libltdl/ltdl.c b/libltdl/ltdl.c
index e1b4e2f..098effa 100644
--- a/libltdl/ltdl.c
+++ b/libltdl/ltdl.c
@@ -216,6 +216,8 @@ int
 lt_dlinit (void)
 {
   int	errors	= 0;
+  const char* saved_error = 0;
+  LT__RESETERROR ();
 
   /* Initialize only at first call. */
   if (++initialized == 1)
@@ -232,6 +234,7 @@ lt_dlinit (void)
       /* Now open all the preloaded module loaders, so the application
 	 can use _them_ to lt_dlopen its own modules.  */
 #ifdef HAVE_LIBDLLOADER
+      LT__GETERROR(saved_error);
       if (!errors)
 	{
 	  errors += lt_dlpreload (preloaded_symbols);
@@ -241,6 +244,7 @@ lt_dlinit (void)
 	{
 	  errors += lt_dlpreload_open (LT_STR(LTDLOPEN), loader_init_callback);
 	}
+      LT__FORCEERROR(saved_error);
 #endif /* HAVE_LIBDLLOADER */
     }
 
@@ -258,6 +262,7 @@ lt_dlexit (void)
   lt_dlloader *loader   = 0;
   lt_dlhandle  handle   = handles;
   int	       errors   = 0;
+  LT__RESETERROR ();
 
   if (!initialized)
     {
@@ -359,7 +364,6 @@ tryall_dlopen (lt_dlhandle *phandle, const char *filename,
 	       lt_dladvise advise, const lt_dlvtable *vtable)
 {
   lt_dlhandle	handle		= handles;
-  const char *	saved_error	= 0;
   int		errors		= 0;
 
 #ifdef LT_DEBUG_LOADERS
@@ -368,7 +372,6 @@ tryall_dlopen (lt_dlhandle *phandle, const char *filename,
 	   vtable ? vtable->name : "(ALL)");
 #endif
 
-  LT__GETERROR (saved_error);
 
   /* check whether the module was already opened */
   for (;handle; handle = handle->next)
@@ -465,8 +468,6 @@ tryall_dlopen (lt_dlhandle *phandle, const char *filename,
     handle->vtable = loader_vtable;
   }
 
-  LT__SETERRORSTR (saved_error);
-
  done:
   return errors;
 }
@@ -844,8 +845,13 @@ load_deplibs (lt_dlhandle handle, char *deplibs)
 	  if (strncmp(p, "-L", 2) == 0 || strncmp(p, "-R", 2) == 0)
 	    {
 	      char save = *end;
+	      const char* saved_error = 0;
+	      int r;
 	      *end = 0; /* set a temporary string terminator */
-	      if (lt_dladdsearchdir(p+2))
+	      LT__GETERROR(saved_error);
+	      r = lt_dladdsearchdir(p+2);
+	      LT__FORCEERROR(saved_error);
+	      if (r)
 		{
 		  goto cleanup;
 		}
@@ -1139,7 +1145,6 @@ static int
 try_dlopen (lt_dlhandle *phandle, const char *filename, const char *ext,
 	    lt_dladvise advise)
 {
-  const char *	saved_error	= 0;
   char *	archive_name	= 0;
   char *	canonical	= 0;
   char *	base_name	= 0;
@@ -1158,7 +1163,6 @@ try_dlopen (lt_dlhandle *phandle, const char *filename, const char *ext,
 	   ext ? ext : "(null)");
 #endif
 
-  LT__GETERROR (saved_error);
 
   /* dlopen self? */
   if (!filename)
@@ -1477,7 +1481,6 @@ try_dlopen (lt_dlhandle *phandle, const char *filename, const char *ext,
       handles		= *phandle;
     }
 
-  LT__SETERRORSTR (saved_error);
 
  cleanup:
   FREE (dir);
@@ -1537,6 +1540,7 @@ int
 lt_dladvise_init (lt_dladvise *padvise)
 {
   lt_dladvise advise = (lt_dladvise) lt__zalloc (sizeof (struct lt__advise));
+  LT__RESETERROR ();
   *padvise = advise;
   return (advise ? 0 : 1);
 }
@@ -1544,6 +1548,7 @@ lt_dladvise_init (lt_dladvise *padvise)
 int
 lt_dladvise_destroy (lt_dladvise *padvise)
 {
+  LT__RESETERROR ();
   if (padvise)
     FREE(*padvise);
   return 0;
@@ -1553,6 +1558,7 @@ int
 lt_dladvise_ext (lt_dladvise *padvise)
 {
   assert (padvise && *padvise);
+  LT__RESETERROR ();
   (*padvise)->try_ext = 1;
   return 0;
 }
@@ -1561,6 +1567,7 @@ int
 lt_dladvise_resident (lt_dladvise *padvise)
 {
   assert (padvise && *padvise);
+  LT__RESETERROR ();
   (*padvise)->is_resident = 1;
   return 0;
 }
@@ -1569,6 +1576,7 @@ int
 lt_dladvise_local (lt_dladvise *padvise)
 {
   assert (padvise && *padvise);
+  LT__RESETERROR ();
   (*padvise)->is_symlocal = 1;
   return 0;
 }
@@ -1577,6 +1585,7 @@ int
 lt_dladvise_global (lt_dladvise *padvise)
 {
   assert (padvise && *padvise);
+  LT__RESETERROR ();
   (*padvise)->is_symglobal = 1;
   return 0;
 }
@@ -1585,6 +1594,7 @@ int
 lt_dladvise_preload (lt_dladvise *padvise)
 {
   assert (padvise && *padvise);
+  LT__RESETERROR ();
   (*padvise)->try_preload_only = 1;
   return 0;
 }
@@ -1606,11 +1616,14 @@ lt_dlopenext (const char *filename)
 {
   lt_dlhandle	handle	= 0;
   lt_dladvise	advise;
+  const char* saved_error = 0;
 
   if (!lt_dladvise_init (&advise) && !lt_dladvise_ext (&advise))
     handle = lt_dlopenadvise (filename, advise);
 
+  LT__GETERROR(saved_error);
   lt_dladvise_destroy (&advise);
+  LT__FORCEERROR(saved_error);
   return handle;
 }
 
@@ -1620,9 +1633,7 @@ lt_dlopenadvise (const char *filename, lt_dladvise advise)
 {
   lt_dlhandle	handle	= 0;
   int		errors	= 0;
-  const char *	saved_error	= 0;
-
-  LT__GETERROR (saved_error);
+  LT__RESETERROR ();
 
   /* Can't have symbols hidden and visible at the same time!  */
   if (advise && advise->is_symlocal && advise->is_symglobal)
@@ -1659,7 +1670,6 @@ lt_dlopenadvise (const char *filename, lt_dladvise advise)
 
 #if defined(LT_MODULE_EXT)
       /* Try appending SHLIB_EXT.   */
-      LT__SETERRORSTR (saved_error);
       errors = try_dlopen (&handle, filename, shlib_ext, advise);
 
       /* As before, if the file was found but loading failed, return now
@@ -1866,6 +1876,7 @@ lt_dlforeachfile (const char *search_path,
 {
   int is_done = 0;
   file_worker_func **fpptr = &func;
+  LT__RESETERROR ();
 
   if (search_path)
     {
@@ -1909,6 +1920,7 @@ lt_dlclose (lt_dlhandle handle)
 {
   lt_dlhandle cur, last;
   int errors = 0;
+  LT__RESETERROR ();
 
   /* check whether the handle is valid */
   last = cur = handles;
@@ -1978,6 +1990,8 @@ lt_dlsym (lt_dlhandle place, const char *symbol)
   lt_user_data data;
   lt_dlhandle handle;
 
+  LT__RESETERROR ();
+
   if (!place)
     {
       LT__SETERROR (INVALID_HANDLE);
@@ -2012,9 +2026,6 @@ lt_dlsym (lt_dlhandle place, const char *symbol)
   data = handle->vtable->dlloader_data;
   if (handle->info.name)
     {
-      const char *saved_error;
-
-      LT__GETERROR (saved_error);
 
       /* this is a libtool module */
       if (handle->vtable->sym_prefix)
@@ -2040,7 +2051,6 @@ lt_dlsym (lt_dlhandle place, const char *symbol)
 	    }
 	  return address;
 	}
-      LT__SETERRORSTR (saved_error);
     }
 
   /* otherwise try "symbol" */
@@ -2054,6 +2064,10 @@ lt_dlsym (lt_dlhandle place, const char *symbol)
       strcpy(sym, symbol);
     }
 
+  /* Reset the dlerror() string, so that errors returned are for the
+   * symbol without the foo_LTX_ prefix */
+  LT__RESETERROR ();
+
   address = handle->vtable->find_sym (data, handle->module, sym);
   if (sym != lsym)
     {
@@ -2148,6 +2162,8 @@ lt_dladdsearchdir (const char *search_dir)
 {
   int errors = 0;
 
+  LT__RESETERROR ();
+
   if (search_dir && *search_dir)
     {
       if (lt_dlpath_insertdir (&user_search_path, 0, search_dir) != 0)
@@ -2161,6 +2177,7 @@ int
 lt_dlinsertsearchdir (const char *before, const char *search_dir)
 {
   int errors = 0;
+  LT__RESETERROR ();
 
   if (before)
     {
@@ -2188,6 +2205,7 @@ int
 lt_dlsetsearchpath (const char *search_path)
 {
   int   errors	    = 0;
+  LT__RESETERROR ();
 
   FREE (user_search_path);
 
@@ -2206,6 +2224,7 @@ const char *
 lt_dlgetsearchpath (void)
 {
   const char *saved_path;
+  LT__RESETERROR ();
 
   saved_path = user_search_path;
 
diff --git a/tests/lt_dlopenext.at b/tests/lt_dlopenext.at
index 26a2b24..66c6c0c 100644
--- a/tests/lt_dlopenext.at
+++ b/tests/lt_dlopenext.at
@@ -120,7 +120,8 @@ main (int argc, const char *argv[])
       errormsg = dlerrordup (errormsg);
       if (errormsg != NULL)
         {
-          errors = lt_dlclose (module);
+	  errors = 1;
+          errors += lt_dlclose (module);
           module = NULL;
         }
     }
_______________________________________________
http://lists.gnu.org/mailman/listinfo/libtool

Reply via email to