Den 2010-01-17 10:31 skrev Ralf Wildenhues:
What does this patch and its followup fix get us?  What behavior changed
in relation to previous code, and if this is fixing a bug, is there need
and chance to test for it?
Previously the reported error was a plain "can't open the module" or
"symbol not found", even though the system might have reported why it
could not open the library or not find the symbol. I would say it's
about the same as using dlerror when present in the dlopen loader.

Ah, ok.  Thanks.

I'm not too fond of adding new static storage and manipulation (yet
another reason lt_dlopen may not be called concurrently from different
threads), or improved functionality without testsuite exposure that we
really improved.  Further, the documentation I found about GetLastError
states W2K as minimum version, so I hope that you checked that this
works with older Windows as well.  Otherwise, I am fine with the patch.

Going back to what this actually brings us...

Previously we had reported errors of "can't open the module" and "symbol not
found". With the patch that turns into "The specified module could not be
found.\r\n" and "The specified procedure could not be found." (WinXP) or
"Module not found\r\n" and "Procedure not found\r\n" (Wine).

The \r\n at the end of the messages should probably be removed. And I did
manage to write a test that exposes this new functionallity - as you
requested - by unloading all modules except the loadlibrary loader (and
the preopen loader). The test is attached.

But, I have not succeeded in generating any other errors than the above
two. I have tried to remove execute bits on the plugin and a dependent
library, and I have tried removing a dependent library. But real problems
usually manifests themselves in weird ways and the correct error message
may be crucial in some unforseen case. Is it worth it?

Cheers,
Peter

--
They are in the crowd with the answer before the question.
> Why do you dislike Jeopardy?
# loadlibrary.at -- test loadlibrary functionality          -*- Autotest -*-
#
#   Copyright (C) 2010 Free Software Foundation, Inc.
#   This file is part of GNU Libtool.
#
# GNU Libtool is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License as
# published by the Free Software Foundation; either version 2 of
# the License, or (at your option) any later version.
#
# GNU Libtool is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with GNU Libtool; see the file COPYING.  If not, a copy
# can be downloaded from  http://www.gnu.org/licenses/gpl.html,
# or obtained by writing to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
####

AT_SETUP([loadlibrary error messages])
AT_KEYWORDS([libltdl])

AT_DATA([main.c],
[[#include <ltdl.h>
#include <stdio.h>

static int
standard_error_message(const char *error)
{
  int error_number;

  for (error_number = 0; error_number < LT_ERROR_MAX; ++error_number)
    {
      lt_dlseterror (error_number);
      if (error == lt_dlerror ())
        {
          return 1;
        }
    }

  lt_dlseterror (LT_ERROR_UNKNOWN);
  return 0;
}

int
main (int argc, char* argv[])
{
  int err = 0;
  lt_dlhandle module = NULL;
  const lt_dlvtable *loadlibrary;
  const lt_dlvtable *preopen;
  lt_dlloader *loader = NULL;
  lt_dlloader *next;
  const lt_dlvtable *vtable;
  void *symbol;
  const char *error;

  if (argc < 2)
    {
      fprintf (stderr, "usage: %s plugin [symbol]\n", argv[0]);
      return 1;
    }

  lt_dlinit ();

  loadlibrary = lt_dlloader_find ("lt_loadlibrary");
  if (!loadlibrary)
    {
      /* Skip if the loadlibrary loader isn't supported */
      printf ("loadlibrary loader not found\n");
      err = 77;
      goto cleanup;
    }

  preopen = lt_dlloader_find ("lt_preopen");
  if (!loadlibrary)
    {
      printf ("preopen loader not found\n");
      err = 2;
      goto cleanup;
    }

  /* Remove all loaders except the preopen and loadlibrary loaders. */
  while (next = lt_dlloader_next (loader))
    {
      if (lt_dlloader_get (next) == loadlibrary)
        {
          loader = next;
          continue;
        }

      if (lt_dlloader_get (next) == preopen)
        {
          loader = next;
          continue;
        }

      lt_dlloader_remove (lt_dlloader_get (next)->name);
    }

  module = lt_dlopen (argv[1]);
  error = lt_dlerror ();

  if (module)
    {
      printf ("lt_dlopen: success!\n");

      if (argc == 2)
        {
          /* But failure was the desired result... */
          err = 2;
          goto cleanup;
        }
    }
  else if (argc > 2)
    {
      /* Didn't expect failure... */
      printf ("lt_dlopen: failure: %s\n", error);
      err = 2;
      goto cleanup;
    }
  else if (standard_error_message (error))
    {
      /* Expected custom error message... */
      printf ("lt_dlopen: standard error (bad): %s\n", error);
      err = 1;
      goto cleanup;
    }
  else
    {
      printf ("lt_dlopen: custom error (good): %s\n", error);
      goto cleanup;
    }

  symbol = lt_dlsym (module, argv[2]);
  error = lt_dlerror ();

  if (symbol)
    {
      printf ("lt_dlsym: success!\n");
    }
  else if (standard_error_message (error))
    {
      /* Expected custom failure message... */
      printf ("lt_dlsym: standard error (bad): %s\n", error);
      err = 1;
    }
  else
    {
      printf ("lt_dlsym: custom error (good): %s\n", error);
    }

cleanup:
  if (module)
    {
      lt_dlclose (module);
    }
  lt_dlexit ();
  return err;
}
]])

AT_DATA([foomod.c],
[[
int foosym (void);
int
foosym (void)
{
  return 0;
}
]])

AT_DATA([bardep.c],
[[
int bardep (void);
int
bardep (void)
{
  return 0;
}
]])

AT_DATA([barmod.c],
[[
int bardep (void);
int barsym (void);
int
barsym (void)
{
  return bardep ();
}
]])

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

CPPFLAGS="$LTDLINCL $CPPFLAGS"
inst=`pwd`/inst
libdir=$inst/lib

AT_CHECK([$CC $CPPFLAGS $CFLAGS -c main.c], [], [ignore], [ignore])
for file in foomod.c bardep.c barmod.c; do
  AT_CHECK([$LIBTOOL --mode=compile $CC $CPPFLAGS $CFLAGS -c $file],
           [], [ignore], [ignore])
done
AT_CHECK([$LIBTOOL --mode=link $CC $CFLAGS $LDFLAGS -o foomod.la ]dnl
         [-rpath $libdir -module -avoid-version -no-undefined ]dnl
         [foomod.lo],
         [], [ignore], [ignore])
AT_CHECK([$LIBTOOL --mode=link $CC $CFLAGS $LDFLAGS -o libbardep.la ]dnl
         [-rpath $libdir -avoid-version -no-undefined ]dnl
         [bardep.lo],
         [], [ignore], [ignore])
AT_CHECK([$LIBTOOL --mode=link $CC $CFLAGS $LDFLAGS -o barmod.la ]dnl
         [-rpath $libdir -module -avoid-version -no-undefined ]dnl
         [barmod.lo ./libbardep.la],
         [], [ignore], [ignore])

AT_CHECK([$LIBTOOL --mode=link $CC $CFLAGS $LDFLAGS -o main$EXEEXT ]dnl
         [main.$OBJEXT $LIBLTDL],
         [], [ignore], [ignore])

LT_AT_EXEC_CHECK([./main], [], [ignore], [ignore], [./foomod.la no_symbol])

dnl Do this portably
chmod -x .libs/foomod.dll
LT_AT_EXEC_CHECK([./main], [], [ignore], [ignore], [./foomod.la])

dnl Do this portably
rm -f .libs/foomod.dll
LT_AT_EXEC_CHECK([./main], [], [ignore], [ignore], [./foomod.la])

LT_AT_EXEC_CHECK([./main], [], [ignore], [ignore], [./barmod.la no_symbol])

dnl Do this portably
chmod -x .libs/cygbardep.dll .libs/libbardep.dll
LT_AT_EXEC_CHECK([./main], [], [ignore], [ignore], [./barmod.la])

dnl Do this portably
rm -f .libs/cygbardep.dll .libs/libbardep.dll
LT_AT_EXEC_CHECK([./main], [], [ignore], [ignore], [./barmod.la])

AT_CLEANUP

Reply via email to