changeset 9958:80432f0ee895

improve octave_shlib for safer shared libs treatment
author Jaroslav Hajek <highegg@gmail.com>
date Thu, 10 Dec 2009 09:14:47 +0100
parents 59ed11557715
children 633f9d837982
files liboctave/ChangeLog liboctave/oct-shlib.cc liboctave/oct-shlib.h src/ChangeLog src/dynamic-ld.cc src/symtab.h
diffstat 6 files changed, 353 insertions(+), 449 deletions(-) [+]
line wrap: on
line diff
--- a/liboctave/ChangeLog	Thu Dec 10 02:09:53 2009 -0500
+++ b/liboctave/ChangeLog	Thu Dec 10 09:14:47 2009 +0100
@@ -1,3 +1,8 @@
+2009-12-09  Jaroslav Hajek  <highegg@gmail.com>
+
+	* oct-shlib.h (octave_shlib): Rewrite.
+	* oct-shlib.cc (octave_shlib): Rewrite.
+
 2009-12-09  John W. Eaton  <jwe@octave.org>
 
 	* oct-time.cc (octave_base_tm::strftime): Call nstrftime instead
--- a/liboctave/oct-shlib.cc	Thu Dec 10 02:09:53 2009 -0500
+++ b/liboctave/oct-shlib.cc	Thu Dec 10 09:14:47 2009 +0100
@@ -1,6 +1,7 @@
 /*
 
 Copyright (C) 1999, 2000, 2002, 2003, 2005, 2006, 2007, 2008 John W. Eaton
+Copyright (C) 2009 VZLU Prague
 
 This file is part of Octave.
 
@@ -60,77 +61,69 @@
 #include "oct-shlib.h"
 #include "str-vec.h"
 
-class
-octave_base_shlib : public octave_shlib
+octave_shlib::shlib_rep::shlib_rep (const std::string& f)
+  : count (1), file (f), tm_loaded ()
 {
-public:
-
-  octave_base_shlib (void)
-    : octave_shlib (octave_xshlib ()), file (), fcn_names (),
-      tm_loaded (static_cast<time_t> (0))
-  { count = 1; }
-
-  octave_base_shlib (const std::string& f)
-    : octave_shlib (octave_xshlib ()), file (f), fcn_names (),
-      tm_loaded (static_cast<time_t> (0))
-  { count = 1; }
-
-  ~octave_base_shlib (void) { }
-
-  void open (const std::string&) { }
-
-  // FIXME -- instead of returning a direct pointer to a function,
-  // perhaps this should return an object containing the pointer.
-  // Then we could do the reference counting without relying on users
-  // of this class to call remove at the appropriate time.  However,
-  // when users accessed the internal pointer, they would still need
-  // to know that the pointer is only valid while the container is
-  // valid (similar to the std::string::c_str method).
-
-  void *search (const std::string&, name_mangler = 0) { return 0; }
-
-  void close (octave_shlib::close_hook = 0) { }
-
-  bool remove (const std::string& fcn_name);
+  instances[f] = this;
 
-  bool is_open (void) const { return false; }
-
-  bool is_out_of_date (void) const;
-
-  size_t number_of_functions_loaded (void) const { return fcn_names.size (); }
-
-  std::string file_name (void) const { return file; }
-
-  octave_time time_loaded (void) const { return tm_loaded; }
-
-protected:
-
-  typedef std::map<std::string, size_t>::iterator fcn_names_iterator;
-  typedef std::map<std::string, size_t>::const_iterator fcn_names_const_iterator;
-
-  std::string file;
-
-  std::map<std::string, size_t> fcn_names;
-
-  octave_time tm_loaded;
-
-  void stamp_time (void);
-
-  void add_to_fcn_names (const std::string& name);
-
-  void do_close_hook (octave_shlib::close_hook = 0);
-
-  void tabula_rasa (void);
-
-  // No copying!
-
-  octave_base_shlib (const octave_base_shlib&);
-
-  octave_base_shlib& operator = (const octave_base_shlib&);
-};
+  if (is_out_of_date ())
+    (*current_liboctave_warning_with_id_handler)
+      ("Octave:warn-future-time-stamp",
+       "timestamp on file %s is in the future", file.c_str ());
+}
 
 bool
-octave_base_shlib::remove (const std::string& fcn_name)
+octave_shlib::shlib_rep::is_out_of_date (void) const
+{
+  file_stat fs (file);
+  return fs.is_newer (tm_loaded);
+}
+
+void
+octave_shlib::shlib_rep::fake_reload (void)
+{
+  // We can't actually reload the library, but we'll pretend we did.
+  file_stat fs (file);
+  if (fs.is_newer (tm_loaded))
+    {
+      tm_loaded = fs.mtime ();
+
+      (*current_liboctave_warning_handler)
+        ("library %s not reloaded due to existing references", file.c_str ());
+    }
+}
+
+octave_shlib::shlib_rep *
+octave_shlib::shlib_rep::get_instance (const std::string& f, bool fake)
+{
+  shlib_rep *retval = 0;
+  std::map<std::string, shlib_rep *>::iterator p = instances.find (f);
+  if (p != instances.end ())
+    {
+      retval = p->second;
+      retval->count++;
+      if (fake)
+        retval->fake_reload ();
+    }
+  else
+    retval = new_instance (f);
+
+  return retval;
+}
+
+void
+octave_shlib::shlib_rep::add_fcn_name (const std::string& name)
+{
+  fcn_names_iterator p = fcn_names.find (name);
+
+  if (p == fcn_names.end ())
+    fcn_names[name] = 1;
+  else
+    ++(p->second);
+}
+
+bool
+octave_shlib::shlib_rep::remove_fcn_name (const std::string& fcn_name)
 {
   bool retval = false;
 
@@ -145,71 +138,35 @@
   return retval;
 }
 
-bool
-octave_base_shlib::is_out_of_date (void) const
-{
-  file_stat fs (file);
-
-  return fs.is_newer (tm_loaded);
-}
-
 void
-octave_base_shlib::stamp_time (void)
-{
-  tm_loaded.stamp ();
-
-  file_stat fs (file);
-
-  if (fs.is_newer (tm_loaded))
-    (*current_liboctave_warning_with_id_handler)
-      ("Octave:warn-future-time-stamp",
-       "timestamp on file %s is in the future", file.c_str ());
-}
-
-void
-octave_base_shlib::add_to_fcn_names (const std::string& name)
-{
-  fcn_names_iterator p = fcn_names.find (name);
-
-  if (p == fcn_names.end ())
-    fcn_names[name] = 1;
-  else
-    ++(p->second);
-}
-
-void
-octave_base_shlib::do_close_hook (octave_shlib::close_hook cl_hook)
+octave_shlib::shlib_rep::do_close_hook (octave_shlib::close_hook cl_hook)
 {
   for (fcn_names_iterator p = fcn_names.begin (); p != fcn_names.end (); p++)
     cl_hook (p->first);
+
+  fcn_names.clear ();
 }
 
-void
-octave_base_shlib::tabula_rasa (void)
-{
-  file = "";
+std::map<std::string, octave_shlib::shlib_rep *> octave_shlib::shlib_rep::instances;
 
-  fcn_names.clear ();
-
-  tm_loaded = static_cast<time_t> (0);
-}
+octave_shlib::shlib_rep octave_shlib::nil_rep;
 
 #if defined (HAVE_DLOPEN_API)
 
 class
-octave_dlopen_shlib : public octave_base_shlib
+octave_dlopen_shlib : public octave_shlib::shlib_rep
 {
 public:
 
-  octave_dlopen_shlib (void);
+  octave_dlopen_shlib (const std::string& f);
 
   ~octave_dlopen_shlib (void);
 
-  void open (const std::string& f);
+  void *search (const std::string& name, octave_shlib::name_mangler mangler = 0);
 
-  void *search (const std::string& name, name_mangler mangler = 0);
-
-  void close (octave_shlib::close_hook cl_hook = 0);
+  // FIXME: this is possibly redundant because failure to open a library will
+  // normally throw an exception, avoiding the construction of an invalid
+  // library. Leave it here for possible future use.
 
   bool is_open (void) const { return (library != 0); }
 
@@ -224,48 +181,36 @@
   void *library;
 };
 
-octave_dlopen_shlib::octave_dlopen_shlib (void)
-  : octave_base_shlib (), library (0)
+octave_dlopen_shlib::octave_dlopen_shlib (const std::string& f)
+  : octave_shlib::shlib_rep (f), library (0)
 {
+  int flags = 0;
+
+  // Use RTLD_NOW to resolve all symbols before dlopen returns.
+  // By using this option, dlopen will detect errors and Octave
+  // won't exit if there are unresolved symbols in the file we are
+  // loading, and we may even get a useful diagnostic.
+#if defined (RTLD_NOW)
+  flags |= RTLD_NOW;
+#endif
+
+  library = dlopen (file.c_str (), flags);
+
+  if (! library)
+    {
+      const char *msg = dlerror ();
+
+      if (! msg)
+        (*current_liboctave_error_handler) ("%s", msg);
+      else
+        (*current_liboctave_error_handler) ("%s: failed to load", file.c_str ());
+    }
 }
 
 octave_dlopen_shlib::~octave_dlopen_shlib (void)
 {
-  close ();
-}
-
-void
-octave_dlopen_shlib::open (const std::string& f)
-{
-  if (! is_open ())
-    {
-      file = f;
-
-      int flags = 0;
-
-      // Use RTLD_NOW to resolve all symbols before dlopen returns.
-      // By using this option, dlopen will detect errors and Octave
-      // won't exit if there are unresolved symbols in the file we are
-      // loading, and we may even get a useful diagnostic.
-#if defined (RTLD_NOW)
-      flags |= RTLD_NOW;
-#endif
-
-      library = dlopen (file.c_str (), flags);
-
-      if (library)
-	stamp_time ();
-      else
-	{
-	  const char *msg = dlerror ();
-
-	  if (msg)
-	    (*current_liboctave_error_handler) ("%s", msg);
-	}
-    }
-  else
-    (*current_liboctave_error_handler)
-      ("shared library %s is already open", file.c_str ());
+  if (library)
+    dlclose (library);
 }
 
 void *
@@ -282,9 +227,6 @@
 	sym_name = mangler (name);
 
       function = dlsym (library, sym_name.c_str ());
-
-      if (function)
-	add_to_fcn_names (name);
     }
   else
     (*current_liboctave_error_handler)
@@ -293,38 +235,18 @@
   return function;
 }
 
-void
-octave_dlopen_shlib::close (octave_shlib::close_hook cl_hook)
-{
-  if (is_open ())
-    {
-      if (cl_hook)
-	do_close_hook (cl_hook);
-
-      dlclose (library);
-
-      library = 0;
-
-      tabula_rasa ();
-    }
-}
-
 #elif defined (HAVE_SHL_LOAD_API)
 
 class
-octave_shl_load_shlib : public octave_base_shlib
+octave_shl_load_shlib : public octave_shlib::shlib_rep
 {
 public:
 
-  octave_shl_load_shlib (void);
+  octave_shl_load_shlib (const std::string& f);
 
   ~octave_shl_load_shlib (void);
 
-  void open (const std::string& f);
-
-  void *search (const std::string& name, name_mangler mangler = 0);
-
-  void close (octave_shlib::close_hook cl_hook = 0);
+  void *search (const std::string& name, octave_shlib::name_mangler mangler = 0);
 
   bool is_open (void) const { return (library != 0); }
 
@@ -339,36 +261,24 @@
   shl_t library;
 };
 
-octave_shl_load_shlib::octave_shl_load_shlib (void)
-  : octave_base_shlib (), library (0)
+octave_shl_load_shlib::octave_shl_load_shlib (const std::string& f)
+  : octave_shlib::shlib_rep (f), library (0)
 {
+  file = f;
+
+  library = shl_load (file.c_str (), BIND_IMMEDIATE, 0L);
+
+  if (! library)
+    {
+      using namespace std;
+      (*current_liboctave_error_handler) ("%s", strerror (errno));
+    }
 }
 
 octave_shl_load_shlib::~octave_shl_load_shlib (void)
 {
-  close ();
-}
-
-void
-octave_shl_load_shlib::open (const std::string& f)
-{
-  if (! is_open ())
-    {
-      file = f;
-
-      library = shl_load (file.c_str (), BIND_IMMEDIATE, 0L);
-
-      if (library)
-	stamp_time ();
-      else
-	{
-	  using namespace std;
-	  (*current_liboctave_error_handler) ("%s", strerror (errno));
-	}
-    }
-  else
-    (*current_liboctave_error_handler)
-      ("shared library %s is already open", file.c_str ());
+  if (library)
+    shl_unload (library);
 }
 
 void *
@@ -386,9 +296,6 @@
 	
       int status = shl_findsym (&library, sym_name.c_str (),
 				TYPE_UNDEFINED, &function);
-
-      if (status == 0)
-	add_to_fcn_names (name);
     }
   else
     (*current_liboctave_error_handler)
@@ -397,38 +304,18 @@
   return function;
 }
 
-void
-octave_shl_load_shlib::close (octave_shlib::close_hook cl_hook)
-{
-  if (is_open ())
-    {
-      if (cl_hook)
-	do_close_hook (cl_hook);
-
-      shl_unload (library);
-
-      library = 0;
-
-      tabula_rasa ();
-    }
-}
-
 #elif defined (HAVE_LOADLIBRARY_API)
 
 class
-octave_w32_shlib: public octave_base_shlib
+octave_w32_shlib: public octave_shlib::shlib_rep
 {
 public:
 
-  octave_w32_shlib (void);
+  octave_w32_shlib (const std::string& f);
 
   ~octave_w32_shlib (void);
 
-  void open (const std::string& f);
-
-  void *search (const std::string& name, name_mangler mangler = 0);
-
-  void close (octave_shlib::close_hook cl_hook = 0);
+  void *search (const std::string& name, octave_shlib::name_mangler mangler = 0);
 
   bool is_open (void) const { return (handle != 0); }
 
@@ -443,57 +330,43 @@
   HINSTANCE handle; 
 };
 
-octave_w32_shlib::octave_w32_shlib (void)
-  : octave_base_shlib (), handle (0)
+octave_w32_shlib::octave_w32_shlib (const std::string& f)
+  : octave_shlib::shlib_rep (f), handle (0)
 {
+  handle = LoadLibrary (file.c_str ());
+
+  if (! handle)
+    {
+      DWORD lastError = GetLastError ();
+      char *msg;
+
+      switch (lastError)
+        {
+        case ERROR_MOD_NOT_FOUND:
+        case ERROR_DLL_NOT_FOUND:
+          msg = "could not find library or dependents";
+          break;
+
+        case ERROR_INVALID_DLL:
+          msg = "library or its dependents are damaged";
+          break;
+
+        case ERROR_DLL_INIT_FAILED:
+          msg = "library initialization routine failed";
+          break;
+
+        default:
+          msg = "library open failed";
+        }
+
+      (*current_liboctave_error_handler) ("%s: %s", msg, file.c_str ());
+    }
 }
 
 octave_w32_shlib::~octave_w32_shlib (void)
 {
-  close ();
-}
-
-void
-octave_w32_shlib::open (const std::string& f)
-{
-  if (! is_open ())
-    {
-      file = f;
-
-      handle = LoadLibrary (file.c_str ());
-
-      if (handle)
-	stamp_time ();
-      else
-	{
-	  DWORD lastError = GetLastError ();
-	  char *msg;
-
-	  switch (lastError)
-	    {
-	    case ERROR_MOD_NOT_FOUND:
-	    case ERROR_DLL_NOT_FOUND:
-	      msg = "could not find library or dependents";
-	      break;
-
-	    case ERROR_INVALID_DLL:
-	      msg = "library or its dependents are damaged";
-	      break;
-
-	    case ERROR_DLL_INIT_FAILED:
-	      msg = "library initialization routine failed";
-	      break;
-
-	    default:
-	      msg = "library open failed";
-	    }
-
-	  (*current_liboctave_error_handler) ("%s: %s", msg, file.c_str ());
-	}
-    }
-  else
-    (*current_liboctave_error_handler)
-      ("shared library %s is already open", file.c_str ());
+  if (handle)
+    FreeLibrary (handle);
 }
 
 extern "C"
@@ -515,9 +388,6 @@
 	sym_name = mangler (name);
 
       function = octave_w32_library_search (handle, sym_name.c_str ());
-
-      if (function)
-	add_to_fcn_names (name);
     }
   else
     (*current_liboctave_error_handler)
@@ -526,26 +396,10 @@
   return function;
 }
 
-void
-octave_w32_shlib::close (octave_shlib::close_hook cl_hook)
-{
-  if (is_open ())
-    {
-      if (cl_hook)
-	do_close_hook (cl_hook);
-
-      FreeLibrary (handle);
-
-      handle = 0;
-
-      tabula_rasa ();
-    }
-}
-
 #elif defined (HAVE_DYLD_API)
 
 class
-octave_dyld_shlib : public octave_base_shlib
+octave_dyld_shlib : public octave_shlib::shlib_rep
 {
 public:
 
@@ -555,11 +409,11 @@
 
   void open (const std::string& f);
 
-  void *search (const std::string& name, name_mangler mangler = 0);
+  void *search (const std::string& name, octave_shlib::name_mangler mangler = 0);
 
   void close (octave_shlib::close_hook cl_hook = 0);
 
-  bool is_open (void) const {return (isOpen); }
+  bool is_open (void) const {return (handle != 0); }
 
 private:
 
@@ -569,70 +423,52 @@
 
   octave_dyld_shlib& operator = (const octave_dyld_shlib&);
 
-  bool isOpen;
   NSObjectFileImage img;
   NSModule handle;
 };
 
-octave_dyld_shlib::octave_dyld_shlib (void)
-  : octave_base_shlib (), isOpen (false), handle (0)
+octave_dyld_shlib::octave_dyld_shlib (const std::string& f)
+  : octave_shlib::shlib_rep (f), handle (0)
 {
+  int returnCode = NSCreateObjectFileImageFromFile (file.c_str (), &img);
+
+  if (NSObjectFileImageSuccess == returnCode)
+    {
+      handle = NSLinkModule (img, file.c_str (),
+                             (NSLINKMODULE_OPTION_RETURN_ON_ERROR
+                              | NSLINKMODULE_OPTION_PRIVATE));
+      if (! handle)
+        {
+          NSLinkEditErrors ler;
+          int lerno;
+          const char *file2;
+          const char *errstr = 0;
+
+          NSLinkEditError (&ler, &lerno, &file2, &errstr);
+
+          if (! errstr)
+            errstr = "unspecified error";
+
+          (*current_liboctave_error_handler)
+            ("%s: %s", file.c_str (), errstr);	
+        }
+    }
+  else
+    {
+      (*current_liboctave_error_handler)
+        ("got NSObjectFileImageReturnCode %d", returnCode);
+
+      // FIXME -- should use NSLinkEditError () to get
+      // more info on what went wrong.
+    }
 }
 
 octave_dyld_shlib::~octave_dyld_shlib (void)
 {
-  close ();
-}
-
-void
-octave_dyld_shlib::open (const std::string& f)
-{
-  int returnCode;
-
-  if (! is_open ())
-    {
-      file = f;
-
-      returnCode = NSCreateObjectFileImageFromFile (file.c_str (), &img);
+  if (handle)
+    NSUnLinkModule (handle, NSUNLINKMODULE_OPTION_RESET_LAZY_REFERENCES);
 
-      if (NSObjectFileImageSuccess == returnCode)
-	{
-	  handle = NSLinkModule (img, file.c_str (),
-				 (NSLINKMODULE_OPTION_RETURN_ON_ERROR
-				  | NSLINKMODULE_OPTION_PRIVATE));
-	  if (handle)
-	    {
-	      stamp_time ();
-	      isOpen = true;
-	    }
-	  else
-	    {
-	      NSLinkEditErrors ler;
-	      int lerno;
-	      const char *file2;
-	      const char *errstr = 0;
-
-	      NSLinkEditError (&ler, &lerno, &file2, &errstr);
-
-	      if (errstr)
-		(*current_liboctave_error_handler)
-		  ("%s: %s", file.c_str (), errstr);	
-	    }
-	}
-      else
-	{
-	  (*current_liboctave_error_handler)
-	    ("got NSObjectFileImageReturnCode %d", returnCode);
-
-	  // FIXME -- should use NSLinkEditError () to get
-	  // more info on what went wrong.
-	}
-    }
-  else
-    {
-      (*current_liboctave_error_handler)
-	("bundle %s is already open", file.c_str ());
-    }
+  NSDestroyObjectFileImage (img);
 }
 
 void *
@@ -653,7 +489,6 @@
       if (symbol)
 	{
 	  function = NSAddressOfSymbol (symbol);
-	  add_to_fcn_names (name);
 	}
     }
   else
@@ -663,39 +498,23 @@
   return function;
 }
 
-void
-octave_dyld_shlib::close (octave_shlib::close_hook cl_hook)
-{
-  if (is_open ())
-    {
-      do_close_hook (cl_hook);
-
-      NSUnLinkModule (handle, NSUNLINKMODULE_OPTION_RESET_LAZY_REFERENCES);
-
-      handle = 0;
-
-      if (NSDestroyObjectFileImage (img))
-	isOpen = false;
-
-      tabula_rasa ();
-    }
-}
-
 #endif
 
-octave_shlib *
-octave_shlib::make_shlib (void)
+octave_shlib::shlib_rep *
+octave_shlib::shlib_rep::new_instance (const std::string& f)
 {
 #if defined (HAVE_DLOPEN_API)
-  return new octave_dlopen_shlib ();
+  return new octave_dlopen_shlib (f);
 #elif defined (HAVE_SHL_LOAD_API)
-  return new octave_shl_load_shlib ();
+  return new octave_shl_load_shlib (f);
 #elif defined (HAVE_LOADLIBRARY_API)
-  return new octave_w32_shlib ();
+  return new octave_w32_shlib (f);
 #elif defined (HAVE_DYLD_API)
-  return new octave_dyld_shlib ();
+  return new octave_dyld_shlib (f);
 #else
-  return new octave_base_shlib ();
+  (*current_liboctave_error_handler)
+    ("no API for dynamic loading is available");
+  return new shlib_rep ();
 #endif
 }
 
--- a/liboctave/oct-shlib.h	Thu Dec 10 02:09:53 2009 -0500
+++ b/liboctave/oct-shlib.h	Thu Dec 10 09:14:47 2009 +0100
@@ -1,6 +1,7 @@
 /*
 
 Copyright (C) 1999, 2000, 2002, 2004, 2005, 2006, 2007, 2008 John W. Eaton
+Copyright (C) 2009 VZLU Prague
 
 This file is part of Octave.
 
@@ -24,43 +25,103 @@
 #define octave_shlib_h 1
 
 #include <string>
+#include <map>
 
 #include "oct-time.h"
 
-// This just provides a way to avoid infinite recursion when building
-// octave_shlib objects.
-
-class
-OCTAVE_API
-octave_xshlib
-{
-public:
-
-  octave_xshlib (void) { }
-};
-
 class
 OCTAVE_API
 octave_shlib
 {
-public:
+public: // FIXME: make this class private?
 
   typedef std::string (*name_mangler) (const std::string&);
-
   typedef void (*close_hook) (const std::string&);
 
-  octave_shlib (void) : relative (false), rep (make_shlib ()) { }
+  class shlib_rep
+  {
+  public:
+
+    shlib_rep (void) 
+      : count (1), file (), tm_loaded (time_t ()) { }
+
+  protected:
+
+    shlib_rep (const std::string& f);
+
+  public:
+
+    virtual ~shlib_rep (void)
+      {
+        instances.erase (file);
+      }
 
-  octave_shlib (const std::string& f)
-    : relative (false), rep (make_shlib ()) { open (f); }
+    virtual bool is_open (void) const
+      { return false; }
+
+    virtual void *search (const std::string&, name_mangler = 0)
+      { return 0; }
+
+    bool is_out_of_date (void) const;
+
+    // This method will be overriden conditionally.
+    static shlib_rep *new_instance (const std::string& f);
+
+    static shlib_rep *get_instance (const std::string& f, bool fake);
+
+    octave_time time_loaded (void) const
+      { return tm_loaded; }
+
+    std::string file_name (void) const
+      { return file; }
+
+    void insert_hook_name (const std::string& name) const;
+
+    void erase_hook_name (const std::string& name) const;
 
-  virtual ~octave_shlib (void)
+    size_t num_fcn_names (void) const { return fcn_names.size (); }
+
+    void add_fcn_name (const std::string&);
+
+    bool remove_fcn_name (const std::string&);
+
+    void do_close_hook (close_hook cl_hook);
+
+  public:
+
+    int count;
+
+  protected:
+
+    void fake_reload (void); 
+
+    std::string file;
+    octave_time tm_loaded;
+
+    // Set of hooked function names.
+    typedef std::map<std::string, size_t>::iterator fcn_names_iterator;
+    typedef std::map<std::string, size_t>::const_iterator fcn_names_const_iterator;
+
+    std::map<std::string, size_t> fcn_names;
+
+    static std::map<std::string, shlib_rep *> instances;
+  };
+
+private:
+
+  static shlib_rep nil_rep;
+
+public:
+
+  octave_shlib (void) : rep (&nil_rep) { rep->count++; }
+
+  octave_shlib (const std::string& f, bool fake = true)
+    : rep (shlib_rep::get_instance (f, fake)) { }
+
+  ~octave_shlib (void)
     {
-      if (rep && --rep->count == 0)
-	{
-	  delete rep;
-	  rep = 0;
-	}
+      if (--rep->count == 0)
+        delete rep;
     }
 
   octave_shlib (const octave_shlib& sl)
@@ -86,51 +147,49 @@
   bool operator == (const octave_shlib& sl) const
     { return (rep == sl.rep); }
 
-  operator bool () const { return is_open (); }
+  operator bool () const { return rep->is_open (); }
+
+  void open (const std::string& f) 
+    { *this = octave_shlib (f); }
 
-  virtual void open (const std::string& f) { rep->open (f); }
+  void close (close_hook cl_hook = 0)
+    { 
+      if (cl_hook)
+        rep->do_close_hook (cl_hook);
 
-  virtual void *search (const std::string& nm, name_mangler mangler = 0)
-    { return rep->search (nm, mangler); }
+      *this = octave_shlib (); 
+    }
 
-  virtual void close (close_hook cl_hook = 0)
-    { rep->close (cl_hook); }
+  void *search (const std::string& nm, name_mangler mangler = 0) const
+    { 
+      void *f = rep->search (nm, mangler); 
+      if (f)
+        rep->add_fcn_name (nm);
+
+      return f;
+    }
 
-  virtual bool remove (const std::string& fcn_name)
-    { return rep->remove (fcn_name); }
+  void add (const std::string& name)
+    { rep->add_fcn_name (name); }
 
-  virtual bool is_out_of_date (void) const
+  bool remove (const std::string& name)
+    { return rep->remove_fcn_name (name); }
+
+  size_t number_of_functions_loaded (void) const
+    { return rep->num_fcn_names (); }
+
+  bool is_out_of_date (void) const
     { return rep->is_out_of_date (); }
 
-  void mark_relative (void) { relative = true; }
-
-  bool is_relative (void) const { return relative; }
-
-  virtual size_t number_of_functions_loaded (void) const
-    { return rep->number_of_functions_loaded (); }
-
-  virtual std::string file_name (void) const
+  std::string file_name (void) const
     { return rep->file_name (); }
 
-  virtual octave_time time_loaded (void) const
+  octave_time time_loaded (void) const
     { return rep->time_loaded (); }
 
-protected:
-
-  octave_shlib (const octave_xshlib&) : rep (0) { }
-
-  virtual bool is_open (void) const { return rep->is_open (); }
-
-  static octave_shlib *make_shlib (void);
+private:
 
-  // TRUE if this function was found from a relative path element.
-  bool relative;
-
-  union
-    {
-      octave_shlib *rep;
-      int count;
-    };
+  shlib_rep *rep;
 };
 
 #endif
--- a/src/ChangeLog	Thu Dec 10 02:09:53 2009 -0500
+++ b/src/ChangeLog	Thu Dec 10 09:14:47 2009 +0100
@@ -1,3 +1,14 @@
+2009-12-09  Jaroslav Hajek  <highegg@gmail.com>
+
+	* symtab.h (symbol_table::fcn_info::clear_autoload_function): New method.
+	(symbol_table::clear_dld_function): New method.
+	* dynamic-ld.cc (octave_shlib_list::do_remove): Switch order of stmts.
+	(octave_mex_file_list::do_remove): Likewise.
+	(do_clear_function): Call symbol_table::clear_dld_function.
+	(octave_dynamic_loader::do_load_oct): Don't use
+	octave_shlib::mark_relative.
+	(octave_dynamic_loader::do_load_mex): Ditto.
+
 2009-12-10  John W. Eaton  <jwe@octave.org>
 
 	* file-io.cc (fopen_mode_to_ios_mode): Allow "+" at the end of
--- a/src/dynamic-ld.cc	Thu Dec 10 02:09:53 2009 -0500
+++ b/src/dynamic-ld.cc	Thu Dec 10 09:14:47 2009 +0100
@@ -107,9 +107,11 @@
     {
       if (*p == shl)
 	{
-	  shl.close (cl_hook);
+          // Erase first to avoid potentially invalidating the pointer by the
+          // following hooks.
+	  lib_list.erase (p);
 
-	  lib_list.erase (p);
+	  shl.close (cl_hook);
 
 	  break;
 	}
@@ -240,9 +242,11 @@
     {
       if (*p == shl)
 	{
-	  shl.close (cl_hook);
+          // Erase first to avoid potentially invalidating the pointer by the
+          // following hooks.
+	  file_list.erase (p);
 
-	  file_list.erase (p);
+	  shl.close (cl_hook);
 
 	  break;
 	}
@@ -309,7 +313,7 @@
 {
   warning_with_id ("Octave:reload-forces-clear", "  %s", fcn_name.c_str ());
 
-  symbol_table::clear_user_function (fcn_name);
+  symbol_table::clear_dld_function (fcn_name);
 }
 
 static void
@@ -346,12 +350,7 @@
       oct_file.open (file_name);
 
       if (! error_state && oct_file)
-	{
-	  octave_shlib_list::append (oct_file);
-
-	  if (relative)
-	    oct_file.mark_relative ();
-	}
+        octave_shlib_list::append (oct_file);
     }
 
   if (! error_state)
@@ -413,12 +412,7 @@
       mex_file.open (file_name);
 
       if (! error_state && mex_file)
-	{
-	  octave_shlib_list::append (mex_file);
-
-	  if (relative)
-	    mex_file.mark_relative ();
-	}
+        octave_shlib_list::append (mex_file);
     }
 
   if (! error_state)
--- a/src/symtab.h	Thu Dec 10 02:09:53 2009 -0500
+++ b/src/symtab.h	Thu Dec 10 09:14:47 2009 +0100
@@ -847,6 +847,8 @@
 
     void clear_user_function (void) { rep->clear_user_function (); }
     
+    void clear_autoload_function (void) { rep->clear_autoload_function (); }
+    
     void clear_mex_function (void) { rep->clear_mex_function (); }
 
     void add_dispatch (const std::string& type, const std::string& fname)
@@ -1392,6 +1394,20 @@
     //   error ("clear: no such function `%s'", name.c_str ());
   }
 
+  // This clears oct and mex files, incl. autoloads.
+  static void clear_dld_function (const std::string& name)
+  {
+    fcn_table_iterator p = fcn_table.find (name);
+
+    if (p != fcn_table.end ())
+      {
+	fcn_info& finfo = p->second;
+
+	finfo.clear_autoload_function ();
+	finfo.clear_user_function ();
+      }
+  }
+
   static void clear_mex_functions (void)
   {
     for (fcn_table_iterator p = fcn_table.begin (); p != fcn_table.end (); p++)