GNU Octave  4.4.1
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
oct-shlib.cc
Go to the documentation of this file.
1 /*
2 
3 Copyright (C) 1999-2018 John W. Eaton
4 Copyright (C) 2009 VZLU Prague
5 
6 This file is part of Octave.
7 
8 Octave is free software: you can redistribute it and/or modify it
9 under the terms of the GNU General Public License as published by
10 the Free Software Foundation, either version 3 of the License, or
11 (at your option) any later version.
12 
13 Octave is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17 
18 You should have received a copy of the GNU General Public License
19 along with Octave; see the file COPYING. If not, see
20 <https://www.gnu.org/licenses/>.
21 
22 */
23 
24 #if defined (HAVE_CONFIG_H)
25 # include "config.h"
26 #endif
27 
28 #include <map>
29 
30 #if defined (HAVE_SHL_LOAD_API)
31 # include <cerrno>
32 # include <cstring>
33 #endif
34 
35 #if defined (HAVE_DYLD_API)
36 # include <mach-o/dyld.h>
37 #endif
38 
39 extern "C"
40 {
41 #if defined (HAVE_DLOPEN_API)
42 # if defined (HAVE_DLFCN_H)
43 # include <dlfcn.h>
44 # else
45 extern void * dlopen (const char *, int);
46 extern const char * dlerror (void);
47 extern void * dlsym (void *, const char *);
48 extern int dlclose (void *);
49 # endif
50 #elif defined (HAVE_SHL_LOAD_API)
51 # include <dl.h>
52 #elif defined (HAVE_LOADLIBRARY_API)
53 # define WIN32_LEAN_AND_MEAN 1
54 # include <windows.h>
55 # include <psapi.h>
56 #endif
57 }
58 
59 #include "file-ops.h"
60 #include "file-stat.h"
61 #include "lo-error.h"
62 #include "oct-shlib.h"
63 #include "str-vec.h"
64 
65 namespace octave
66 {
68  : count (1), file (f), tm_loaded (), fcn_names (), search_all_loaded (false)
69  {
70  instances[f] = this;
71 
72  if (is_out_of_date ())
73  (*current_liboctave_warning_with_id_handler)
74  ("Octave:warn-future-time-stamp",
75  "timestamp on file %s is in the future", file.c_str ());
76  }
77 
78  bool
80  {
82  return (fs && fs.is_newer (tm_loaded));
83  }
84 
85  void
87  {
88  // We can't actually reload the library, but we'll pretend we did.
90  if (fs && fs.is_newer (tm_loaded))
91  {
92  tm_loaded = fs.mtime ();
93 
94  (*current_liboctave_warning_with_id_handler)
95  ("Octave:library-reload",
96  "library %s not reloaded due to existing references", file.c_str ());
97  }
98  }
99 
102  {
103  dynlib_rep *retval = nullptr;
104  std::map<std::string, dynlib_rep *>::iterator p = instances.find (f);
105  if (p != instances.end ())
106  {
107  retval = p->second;
108  retval->count++;
109  if (fake)
110  retval->fake_reload ();
111  }
112  else
113  retval = new_instance (f);
114 
115  return retval;
116  }
117 
118  std::list<std::string>
120  {
121  std::list<std::string> retval;
122 
123  for (const auto& p : fcn_names)
124  retval.push_back (p.first);
125 
126  return retval;
127  }
128 
129  void
131  {
132  auto p = fcn_names.find (name);
133 
134  if (p == fcn_names.end ())
135  fcn_names[name] = 1;
136  else
137  ++(p->second);
138  }
139 
140  bool
142  {
143  bool retval = false;
144 
145  auto p = fcn_names.find (fcn_name);
146 
147  if (p != fcn_names.end () && --(p->second) == 0)
148  {
149  fcn_names.erase (fcn_name);
150  retval = true;
151  }
152 
153  return retval;
154  }
155 
156  std::map<std::string, dynamic_library::dynlib_rep *>
158 
160 
161 #if defined (HAVE_DLOPEN_API)
162 
163  class
164  octave_dlopen_shlib : public dynamic_library::dynlib_rep
165  {
166  public:
167 
168  octave_dlopen_shlib (const std::string& f);
169 
170  // No copying!
171 
172  octave_dlopen_shlib (const octave_dlopen_shlib&) = delete;
173 
174  octave_dlopen_shlib& operator = (const octave_dlopen_shlib&) = delete;
175 
176  ~octave_dlopen_shlib (void);
177 
178  void * search (const std::string& name,
179  dynamic_library::name_mangler mangler = nullptr);
180 
181  // FIXME: this is possibly redundant because failure to open a library will
182  // normally throw an exception, avoiding the construction of an invalid
183  // library. Leave it here for possible future use.
184 
185  bool is_open (void) const
186  {
187  return (search_all_loaded || library != nullptr);
188  }
189 
190  private:
191 
192  void *library;
193  };
194 
195  octave_dlopen_shlib::octave_dlopen_shlib (const std::string& f)
196  : dynamic_library::dynlib_rep (f), library (nullptr)
197  {
198  int flags = 0;
199 
200  // Use RTLD_NOW to resolve all symbols before dlopen returns.
201  // By using this option, dlopen will detect errors and Octave
202  // won't exit if there are unresolved symbols in the file we are
203  // loading, and we may even get a useful diagnostic.
204 # if defined (RTLD_NOW)
205  flags |= RTLD_NOW;
206 # endif
207 
208  // Use RTLD_GLOBAL to export symbols from loaded objects so they are
209  // available to other subsequently loaded libraries.
210 # if defined (RTLD_GLOBAL)
211  flags |= RTLD_GLOBAL;
212 # endif
213 
214  if (file.empty ())
215  {
216  search_all_loaded = true;
217  return;
218  }
219 
220  library = dlopen (file.c_str (), flags);
221 
222  if (! library)
223  {
224  const char *msg = dlerror ();
225 
226  if (msg)
227  (*current_liboctave_error_handler) ("%s: failed to load: %s",
228  file.c_str (), msg);
229  else
230  (*current_liboctave_error_handler) ("%s: failed to load",
231  file.c_str ());
232  }
233  }
234 
235  octave_dlopen_shlib::~octave_dlopen_shlib (void)
236  {
237  if (library)
238  dlclose (library);
239  }
240 
241  void *
244  {
245  void *function = nullptr;
246 
247  if (! is_open ())
248  (*current_liboctave_error_handler)
249  ("shared library %s is not open", file.c_str ());
250 
251  std::string sym_name = name;
252 
253  if (mangler)
254  sym_name = mangler (name);
255 
256  if (search_all_loaded)
257  function = dlsym (RTLD_DEFAULT, sym_name.c_str ());
258  else
259  function = dlsym (library, sym_name.c_str ());
260 
261  return function;
262  }
263 
264 #elif defined (HAVE_SHL_LOAD_API)
265 
266  class
267  octave_shl_load_shlib : public dynamic_library::dynlib_rep
268  {
269  public:
270 
271  octave_shl_load_shlib (const std::string& f);
272 
273  // No copying!
274 
275  octave_shl_load_shlib (const octave_shl_load_shlib&) = delete;
276 
277  octave_shl_load_shlib& operator = (const octave_shl_load_shlib&) = delete;
278 
279  ~octave_shl_load_shlib (void);
280 
281  void * search (const std::string& name,
282  dynamic_library::name_mangler mangler = 0);
283 
284  bool is_open (void) const { return (search_all_loaded || library != 0); }
285 
286  private:
287 
288  shl_t library;
289  };
290 
291  octave_shl_load_shlib::octave_shl_load_shlib (const std::string& f)
292  : dynamic_library::dynlib_rep (f), library (0)
293  {
294  file = f;
295 
296  if (file.empty())
297  {
298  search_all_loaded = true;
299  return;
300  }
301 
302  library = shl_load (file.c_str (), BIND_IMMEDIATE, 0L);
303 
304  if (! library)
305  {
306  using namespace std; // FIXME: Why have this line?
307  (*current_liboctave_error_handler) ("%s", std::strerror (errno));
308  }
309  }
310 
311  octave_shl_load_shlib::~octave_shl_load_shlib (void)
312  {
313  if (library)
314  shl_unload (library);
315  }
316 
317  void *
320  {
321  void *function = nullptr;
322 
323  if (! is_open ())
324  (*current_liboctave_error_handler)
325  ("shared library %s is not open", file.c_str ());
326 
327  std::string sym_name = name;
328 
329  if (mangler)
330  sym_name = mangler (name);
331 
332  if (search_all_loaded)
333  int status = shl_findsym (nullptr, sym_name.c_str (),
334  TYPE_UNDEFINED, &function);
335  else
336  int status = shl_findsym (&library, sym_name.c_str (),
337  TYPE_UNDEFINED, &function);
338 
339  return function;
340  }
341 
342 #elif defined (HAVE_LOADLIBRARY_API)
343 
344  class
345  octave_w32_shlib: public dynamic_library::dynlib_rep
346  {
347  public:
348 
349  octave_w32_shlib (const std::string& f);
350 
351  // No copying!
352 
353  octave_w32_shlib (const octave_w32_shlib&) = delete;
354 
355  octave_w32_shlib& operator = (const octave_w32_shlib&) = delete;
356 
357  ~octave_w32_shlib (void);
358 
359  void * search (const std::string& name,
360  dynamic_library::name_mangler mangler = nullptr);
361 
362  void * global_search (const std::string& sym_name);
363 
364  bool is_open (void) const { return (search_all_loaded || handle != nullptr); }
365 
366  private:
367 
368  HINSTANCE handle;
369  };
370 
371  static void
372  set_dll_directory (const std::string& dir = "")
373  {
374  SetDllDirectory (dir.empty () ? nullptr : dir.c_str ());
375  }
376 
377  octave_w32_shlib::octave_w32_shlib (const std::string& f)
378  : dynamic_library::dynlib_rep (f), handle (nullptr)
379  {
380  if (f.empty())
381  {
382  search_all_loaded = true;
383  return;
384  }
385 
387 
388  set_dll_directory (dir);
389 
390  handle = LoadLibrary (file.c_str ());
391 
392  set_dll_directory ();
393 
394  if (! handle)
395  {
396  DWORD lastError = GetLastError ();
397  const char *msg;
398 
399  switch (lastError)
400  {
401  case ERROR_MOD_NOT_FOUND:
402  case ERROR_DLL_NOT_FOUND:
403  msg = "could not find library or dependencies";
404  break;
405 
406  case ERROR_INVALID_DLL:
407  msg = "library or its dependencies are damaged";
408  break;
409 
410  case ERROR_DLL_INIT_FAILED:
411  msg = "library initialization routine failed";
412  break;
413 
414  default:
415  msg = "library open failed";
416  }
417 
418  (*current_liboctave_error_handler) ("%s: %s", msg, file.c_str ());
419  }
420  }
421 
422  octave_w32_shlib::~octave_w32_shlib (void)
423  {
424  if (handle)
425  FreeLibrary (handle);
426  }
427 
428  void *
429  octave_w32_shlib::global_search (const std::string& sym_name)
430  {
431  void *function = nullptr;
432 
433  HANDLE proc = GetCurrentProcess ();
434 
435  if (! proc)
436  (*current_liboctave_error_handler)
437  ("Unable to get handle to own process.");
438 
439  size_t lib_num = 64;
440  size_t size_lib = sizeof (HMODULE);
441  HMODULE *h_libs;
442  DWORD bytes_all_libs;
443  bool got_libs;
444 
445  // Get a list of all the libraries in own process.
446  h_libs = static_cast<HMODULE *> (malloc (size_lib*lib_num));
447  got_libs = EnumProcessModules (proc, h_libs, size_lib*lib_num,
448  &bytes_all_libs);
449  int ii = 0;
450  while (((size_lib*lib_num) < bytes_all_libs) && ii++ < 3)
451  {
452  lib_num = bytes_all_libs / size_lib;
453  h_libs = static_cast<HMODULE *> (realloc (h_libs, bytes_all_libs));
454  got_libs = EnumProcessModules (proc, h_libs, bytes_all_libs,
455  &bytes_all_libs);
456  }
457 
458  if (got_libs)
459  {
460  for (size_t i = 0; i < (bytes_all_libs / size_lib); i++)
461  {
462  // Check for function in library.
463  function = reinterpret_cast<void *>
464  (GetProcAddress (h_libs[i], sym_name.c_str ()));
465 
466  if (function)
467  break;
468  }
469  }
470 
471  // Release the handle to the process.
472  CloseHandle (proc);
473 
474  return function;
475  }
476 
477  void *
480  {
481  void *function = nullptr;
482 
483  if (! search_all_loaded && ! is_open ())
484  (*current_liboctave_error_handler)
485  ("shared library %s is not open", file.c_str ());
486 
487  std::string sym_name = name;
488 
489  if (mangler)
490  sym_name = mangler (name);
491 
492  if (search_all_loaded)
493  function = global_search (sym_name);
494  else
495  function = reinterpret_cast<void *> (GetProcAddress (handle,
496  sym_name.c_str ()));
497 
498  return function;
499  }
500 
501 #elif defined (HAVE_DYLD_API)
502 
503  class
504  octave_dyld_shlib : public dynamic_library::dynlib_rep
505  {
506  public:
507 
508  octave_dyld_shlib (void);
509 
510  // No copying!
511 
512  octave_dyld_shlib (const octave_dyld_shlib&) = delete;
513 
514  octave_dyld_shlib& operator = (const octave_dyld_shlib&) = delete;
515 
516  ~octave_dyld_shlib (void);
517 
518  void open (const std::string& f);
519 
520  void * search (const std::string& name,
521  dynamic_library::name_mangler mangler = nullptr);
522 
523  void close (void);
524 
525  bool is_open (void) const { return (search_all_loaded || handle != 0); }
526 
527  private:
528 
529  NSObjectFileImage img;
530  NSModule handle;
531  };
532 
533  octave_dyld_shlib::octave_dyld_shlib (const std::string& f)
534  : dynamic_library::dynlib_rep (f), handle (0)
535  {
536  if (f.empty ())
538  ("global search is not implemented for DYLD_API");
539 
540  int returnCode = NSCreateObjectFileImageFromFile (file.c_str (), &img);
541 
542  if (NSObjectFileImageSuccess != returnCode)
543  {
544  (*current_liboctave_error_handler)
545  ("got NSObjectFileImageReturnCode %d", returnCode);
546 
547  // FIXME: should use NSLinkEditError () to get
548  // more info on what went wrong.
549  }
550 
551  handle = NSLinkModule (img, file.c_str (),
552  (NSLINKMODULE_OPTION_RETURN_ON_ERROR
553  | NSLINKMODULE_OPTION_PRIVATE));
554  if (! handle)
555  {
556  NSLinkEditErrors ler;
557  int lerno;
558  const char *file2;
559  const char *errstr = nullptr;
560 
561  NSLinkEditError (&ler, &lerno, &file2, &errstr);
562 
563  if (! errstr)
564  errstr = "unspecified error";
565 
566  (*current_liboctave_error_handler) ("%s: %s", file.c_str (), errstr);
567  }
568  }
569 
570  octave_dyld_shlib::~octave_dyld_shlib (void)
571  {
572  if (handle)
573  NSUnLinkModule (handle, NSUNLINKMODULE_OPTION_RESET_LAZY_REFERENCES);
574 
575  NSDestroyObjectFileImage (img);
576  }
577 
578  void *
581  {
582  void *function = nullptr;
583 
584  if (! is_open ())
585  (*current_liboctave_error_handler)
586  ("bundle %s is not open", file.c_str ());
587 
588  std::string sym_name = name;
589 
590  if (mangler)
591  sym_name = mangler (name);
592 
593  NSSymbol symbol = NSLookupSymbolInModule (handle, sym_name.c_str ());
594 
595  if (symbol)
596  {
597  function = NSAddressOfSymbol (symbol);
598  }
599 
600  return function;
601  }
602 
603 #endif
604 
605  dynamic_library::dynlib_rep *
607  {
608 #if defined (HAVE_DLOPEN_API)
609  return new octave_dlopen_shlib (f);
610 #elif defined (HAVE_SHL_LOAD_API)
611  return new octave_shl_load_shlib (f);
612 #elif defined (HAVE_LOADLIBRARY_API)
613  return new octave_w32_shlib (f);
614 #elif defined (HAVE_DYLD_API)
615  return new octave_dyld_shlib (f);
616 #else
617  (*current_liboctave_error_handler)
618  ("support for dynamically loaded libraries was unavailable or disabled when liboctave was built");
619 #endif
620  }
621 }
For example cd octave end example noindent changes the current working directory to file
Definition: dirfns.cc:124
virtual bool is_open(void) const
Definition: oct-shlib.h:66
std::list< std::string > function_names(void) const
Definition: oct-shlib.cc:119
F77_RET_T const F77_REAL const F77_REAL F77_REAL &F77_RET_T const F77_DBLE const F77_DBLE F77_DBLE &F77_RET_T const F77_DBLE F77_DBLE &F77_RET_T const F77_REAL F77_REAL &F77_RET_T const F77_DBLE const F77_DBLE * f
OCTAVE_NORETURN liboctave_error_handler current_liboctave_error_handler
Definition: lo-error.c:38
static std::map< std::string, dynlib_rep * > instances
Definition: oct-shlib.h:112
STL namespace.
std::string dirname(const std::string &path)
Definition: file-ops.cc:353
std::list< std::string > close(void)
Definition: oct-shlib.h:161
void add_fcn_name(const std::string &)
Definition: oct-shlib.cc:130
virtual void * search(const std::string &, name_mangler=nullptr)
Definition: oct-shlib.h:69
nd deftypefn *std::string name
Definition: sysdep.cc:647
is false
Definition: cellfun.cc:400
octave_value retval
Definition: data.cc:6246
static std::list< std::string > search(const std::string &path, const std::string &original_name, bool all)
Definition: kpse.cc:395
static dynlib_rep nil_rep
Definition: oct-shlib.h:118
std::string(* name_mangler)(const std::string &)
Definition: oct-shlib.h:44
p
Definition: lu.cc:138
void open(const std::string &f)
Definition: oct-shlib.h:158
octave::sys::file_stat fs(filename)
for i
Definition: data.cc:5264
is a function handle
Definition: bsxfun.cc:337
bool remove_fcn_name(const std::string &)
Definition: oct-shlib.cc:141
static dynlib_rep * get_instance(const std::string &f, bool fake)
Definition: oct-shlib.cc:101
If this string is the system will ring the terminal sometimes it is useful to be able to print the original representation of the string
Definition: utils.cc:888
sys::time mtime(void) const
Definition: file-stat.h:128
void * search(const std::string &nm, name_mangler mangler=nullptr) const
Definition: oct-shlib.h:172
bool is_newer(const sys::time &time) const
Definition: file-stat.h:149
dynamic_library & operator=(const dynamic_library &sl)
Definition: oct-shlib.h:139
static dynlib_rep * new_instance(const std::string &f)
Definition: oct-shlib.cc:606