libtool
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Unhelpful error message in libltdl


From: John Bytheway
Subject: Re: Unhelpful error message in libltdl
Date: Sat, 08 Mar 2008 21:18:12 +0200
User-agent: Mozilla-Thunderbird 2.0.0.9 (X11/20080110)

Ralf Wildenhues wrote:
> Hello John,
> 
> * John Bytheway wrote on Tue, Jan 29, 2008 at 10:54:05PM CET:
>> I've been using libtool and libltdl to load libraries at runtime in a  
>> project I'm working on, and encountered circumstances where the error  
>> messages are less helpful than they might be.
>>
>> Looking at CVS HEAD, The problem is in find_module.  It calls  
>> tryall_dlopen_module in one of two "normal" ways first, and if they  
>> fail, tries another way on the off chance it was moved to another  
>> directory.  If the first attempt fails due, e.g., to an undefined  
>> symbol, then the second attempt leaves the error message saying "file  
>> not found".  It would be more helpful to have the message about the  
>> undefined symbol.
>>
>> A similar problem exists in lt_dlopenadvise, and mimicking the solution  
>> from that seems like the best answer.  I've made my best shot at this,  
>> and a diff on CVS HEAD is attached.  I've run the tests with this change  
>> and everything seems OK.
> 
> Thanks for the bug report and patch.

Thanks for noticing it :).

> I've given your bug description a
> shot at a test that exposes this issue, but have so far failed.  Below
> is where I'm at, patch against current HEAD.  Can you point me to how
> your setup is different?  Specifically, how do you get a failure of
> dlopen due to an undefined symbol on GNU/Linux when RTLD_NOW is not set?

Ah, yes.  I hadn't realised quite how tricky it is; one answer (the one
that I encountered) is to have an undefined reference to a vtable in
C++.  I've included a patch below on your proposed lt_dlopen.at which
uses this method.  I'll leave it to someone else to try to construct an
equivalent example in C.  I had to make my best guess at the correct
syntax for compiling C++ in this context (I've never encountered
autotest before).  Note also that I removed dep.c and associated stuff
which seemed to be an unnecessary extra level of confusion.

However, this is not the end of the story.  If you run this test you
should see the "file not found" error which was exactly the unhelpful
error which my original patch was supposed to fix, so clearly something
still isn't right.

I spent a while single-stepping with gdb and discovered the problem in
tryall_dlopen, specifically the do loop at about line 418.  It loops
over different loaders, trying each in turn.  In this case the first
loader tried is the dlopen loader, which is the right one, and which
returns the undefined symbol error.  It then tries the preopen loader,
which fails (as it should) but replaces the error with a file not found
error (which seems like a very strange error for it to return, but I'm
sure there's a good reason for it...).

I tried pulling the same trick again, adding a check each time round the
loop that breaks out of it it the loader returns an error other than
file not found (patch for that is also below).  Unfortunately, this
causes it to fail in a different way.  Specifically, it results in a
different sort of file not found error, referring to

testsuite.dir/38/mod/.libs/.libs/libmod1.so

I suspect that this is a type of error which doesn't cause
file_not_found() to return true, and thus the additional check I added
is causing a premature abort.  I didn't try to investigate any more deeply.

However, I also tried running the executable which the test had created
'by hand' (rather than through the test infrastructure) from inside the
directory containing libmod1.la, and then it printed the undefined
symbol error as I had hoped it would; clearly the means by which the
library is opened in the context of the testing is somehow different.

John

Two diffs follow:

--- lt_dlopen.at.orig   2008-03-08 16:55:40.000000000 +0000
+++ lt_dlopen.at        2008-03-08 18:28:43.000000000 +0000
@@ -86,37 +86,25 @@

   return errors;
 }
 ]])

-AT_DATA([mod1.c],
-[[#ifdef __cplusplus
-extern "C" {
-#endif
-extern int i, h (void);
-int j = 1;
-int g (void)
-{
-  return h () + i + j;
-}
-#ifdef __cplusplus
-}
-#endif
-]])
+AT_DATA([mod1.cpp],
+[[struct A {
+  virtual ~A();
+};

-AT_DATA([dep.c],
-[[#ifdef __cplusplus
 extern "C" {
-#endif
-int i = 1;
-int f (void)
+
+int g()
 {
-  return i;
+  A* a = new A();
+  delete a;
+  return 0;
 }
-#ifdef __cplusplus
+
 }
-#endif
 ]])

 : ${LTDLINCL="-I$abs_top_srcdir/libltdl"}
 : ${LIBLTDL="$abs_builddir/../libltdl/libltdlc.la"}

@@ -125,19 +113,15 @@
 instdir=`pwd`/inst
 libdir=$instdir/lib
 mkdir mod lib inst inst/bin inst/lib

 $CC $CPPFLAGS $CFLAGS -c main.c
-for file in mod1.c dep.c; do
-  $LIBTOOL --mode=compile $CC $CPPFLAGS $CFLAGS -c $file
-done
+$LIBTOOL --mode=compile $CXX $CPPFLAGS $CXXFLAGS -c mod1.cpp

 # TODO: do this for versioned libs as well!
-AT_CHECK([$LIBTOOL --mode=link $CC $CFLAGS $LDFLAGS -o lib/libdepend.la \
-          dep.lo -rpath $libdir -avoid-version], [], [ignore], [ignore])
-AT_CHECK([$LIBTOOL --mode=link $CC -module -shared $CFLAGS $LDFLAGS -o
mod/libmod1.la \
-          mod1.lo lib/libdepend.la -rpath $libdir -avoid-version],
+AT_CHECK([$LIBTOOL --mode=link $CXX -module -shared $CXXFLAGS $LDFLAGS
-o mod/libmod1.la \
+          mod1.lo -rpath $libdir -avoid-version],
          [], [ignore], [ignore])

 AT_CHECK([$LIBTOOL --mode=link $CC $CFLAGS $LDFLAGS -o main main.$OBJEXT \
          -dlopen mod/libmod1.la $LIBLTDL], [], [ignore], [ignore])






--- ltdl.c.orig_patch   2008-03-08 17:31:36.000000000 +0000
+++ ltdl.c      2008-03-08 19:03:17.000000000 +0000
@@ -442,10 +442,15 @@
                handle->info.is_symglobal = advise->is_symglobal;
                handle->info.is_symlocal  = advise->is_symlocal;
              }
            break;
          }
+       else if (!file_not_found())
+         {
+           loader = 0;
+           break;
+         }
       }
     while (!vtable && (loader = lt_dlloader_next (loader)));

     /* If VTABLE was given but couldn't open the module, or VTABLE wasn't
        given but we exhausted all loaders without opening the module, bail





reply via email to

[Prev in Thread] Current Thread [Next in Thread]