GNU Octave  6.2.0
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-2021 The Octave Project Developers
4 //
5 // See the file COPYRIGHT.md in the top-level directory of this
6 // distribution or <https://octave.org/copyright/>.
7 //
8 // This file is part of Octave.
9 //
10 // Octave is free software: you can redistribute it and/or modify it
11 // under the terms of the GNU General Public License as published by
12 // the Free Software Foundation, either version 3 of the License, or
13 // (at your option) any later version.
14 //
15 // Octave is distributed in the hope that it will be useful, but
16 // WITHOUT ANY WARRANTY; without even the implied warranty of
17 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 // GNU General Public License for more details.
19 //
20 // You should have received a copy of the GNU General Public License
21 // along with Octave; see the file COPYING. If not, see
22 // <https://www.gnu.org/licenses/>.
23 //
24 ////////////////////////////////////////////////////////////////////////
25 
26 #if defined (HAVE_CONFIG_H)
27 # include "config.h"
28 #endif
29 
30 #include <map>
31 
32 extern "C"
33 {
34 #if defined (HAVE_DLOPEN_API)
35 # if defined (HAVE_DLFCN_H)
36 # include <dlfcn.h>
37 # else
38 extern void * dlopen (const char *, int);
39 extern const char * dlerror (void);
40 extern void * dlsym (void *, const char *);
41 extern int dlclose (void *);
42 # endif
43 #elif defined (HAVE_LOADLIBRARY_API)
44 # define WIN32_LEAN_AND_MEAN 1
45 # include <windows.h>
46 # include <psapi.h>
47 #endif
48 }
49 
50 #include "file-ops.h"
51 #include "file-stat.h"
52 #include "lo-error.h"
53 #include "oct-shlib.h"
54 #include "str-vec.h"
55 
56 #if defined (HAVE_LOADLIBRARY_API)
57 # include "lo-sysdep.h"
58 #endif
59 
60 namespace octave
61 {
63  : m_count (1), m_fcn_names (), m_file (f), m_time_loaded (),
64  m_search_all_loaded (false)
65  {
66  s_instances[f] = this;
67 
68  if (is_out_of_date ())
69  (*current_liboctave_warning_with_id_handler)
70  ("Octave:warn-future-time-stamp",
71  "timestamp on file %s is in the future", m_file.c_str ());
72  }
73 
74  bool
76  {
77  sys::file_stat fs (m_file);
78  return (fs && fs.is_newer (m_time_loaded));
79  }
80 
81  void
83  {
84  // We can't actually reload the library, but we'll pretend we did.
85  sys::file_stat fs (m_file);
86  if (fs && fs.is_newer (m_time_loaded))
87  {
88  m_time_loaded = fs.mtime ();
89 
90  (*current_liboctave_warning_with_id_handler)
91  ("Octave:library-reload",
92  "library %s not reloaded due to existing references", m_file.c_str ());
93  }
94  }
95 
97  dynamic_library::dynlib_rep::get_instance (const std::string& f, bool fake)
98  {
99  dynlib_rep *retval = nullptr;
100  std::map<std::string, dynlib_rep *>::iterator p = s_instances.find (f);
101  if (p != s_instances.end ())
102  {
103  retval = p->second;
104  retval->m_count++;
105  if (fake)
106  retval->fake_reload ();
107  }
108  else
109  retval = new_instance (f);
110 
111  return retval;
112  }
113 
114  std::list<std::string>
116  {
117  std::list<std::string> retval;
118 
119  for (const auto& p : m_fcn_names)
120  retval.push_back (p.first);
121 
122  return retval;
123  }
124 
125  void
127  {
128  auto p = m_fcn_names.find (name);
129 
130  if (p == m_fcn_names.end ())
131  m_fcn_names[name] = 1;
132  else
133  ++(p->second);
134  }
135 
136  bool
137  dynamic_library::dynlib_rep::remove_fcn_name (const std::string& fcn_name)
138  {
139  bool retval = false;
140 
141  auto p = m_fcn_names.find (fcn_name);
142 
143  if (p != m_fcn_names.end () && --(p->second) == 0)
144  {
145  m_fcn_names.erase (fcn_name);
146  retval = true;
147  }
148 
149  return retval;
150  }
151 
152  std::map<std::string, dynamic_library::dynlib_rep *>
154 
156 
157 #if defined (HAVE_DLOPEN_API)
158 
159  class
160  octave_dlopen_shlib : public dynamic_library::dynlib_rep
161  {
162  public:
163 
164  octave_dlopen_shlib (const std::string& f);
165 
166  // No copying!
167 
168  octave_dlopen_shlib (const octave_dlopen_shlib&) = delete;
169 
170  octave_dlopen_shlib& operator = (const octave_dlopen_shlib&) = delete;
171 
172  ~octave_dlopen_shlib (void);
173 
174  void * search (const std::string& name,
175  const dynamic_library::name_mangler& mangler
177 
178  // FIXME: this is possibly redundant because failure to open a library will
179  // normally throw an exception, avoiding the construction of an invalid
180  // library. Leave it here for possible future use.
181 
182  bool is_open (void) const
183  {
184  return (m_search_all_loaded || m_library != nullptr);
185  }
186 
187  private:
188 
189  void *m_library;
190  };
191 
192  octave_dlopen_shlib::octave_dlopen_shlib (const std::string& f)
193  : dynamic_library::dynlib_rep (f), m_library (nullptr)
194  {
195  int flags = 0;
196 
197  // Use RTLD_NOW to resolve all symbols before dlopen returns.
198  // By using this option, dlopen will detect errors and Octave
199  // won't exit if there are unresolved symbols in the file we are
200  // loading, and we may even get a useful diagnostic.
201 # if defined (RTLD_NOW)
202  flags |= RTLD_NOW;
203 # endif
204 
205  // Use RTLD_GLOBAL to export symbols from loaded objects so they are
206  // available to other subsequently loaded libraries.
207 # if defined (RTLD_GLOBAL)
208  flags |= RTLD_GLOBAL;
209 # endif
210 
211  if (m_file.empty ())
212  {
213  m_search_all_loaded = true;
214  return;
215  }
216 
217  m_library = dlopen (m_file.c_str (), flags);
218 
219  if (! m_library)
220  {
221  const char *msg = dlerror ();
222 
223  if (msg)
224  (*current_liboctave_error_handler) ("%s: failed to load: %s",
225  m_file.c_str (), msg);
226  else
227  (*current_liboctave_error_handler) ("%s: failed to load",
228  m_file.c_str ());
229  }
230  }
231 
232  octave_dlopen_shlib::~octave_dlopen_shlib (void)
233  {
234  if (m_library)
235  dlclose (m_library);
236  }
237 
238  void *
239  octave_dlopen_shlib::search (const std::string& name,
240  const dynamic_library::name_mangler& mangler)
241  {
242  void *function = nullptr;
243 
244  if (! is_open ())
245  (*current_liboctave_error_handler)
246  ("shared library %s is not open", m_file.c_str ());
247 
248  std::string sym_name = name;
249 
250  if (mangler)
251  sym_name = mangler (name);
252 
253  if (m_search_all_loaded)
254  function = dlsym (RTLD_DEFAULT, sym_name.c_str ());
255  else
256  function = dlsym (m_library, sym_name.c_str ());
257 
258  return function;
259  }
260 
261 #elif defined (HAVE_LOADLIBRARY_API)
262 
263  class
264  octave_w32_shlib: public dynamic_library::dynlib_rep
265  {
266  public:
267 
268  octave_w32_shlib (const std::string& f);
269 
270  // No copying!
271 
272  octave_w32_shlib (const octave_w32_shlib&) = delete;
273 
274  octave_w32_shlib& operator = (const octave_w32_shlib&) = delete;
275 
276  ~octave_w32_shlib (void);
277 
278  void * search (const std::string& name,
279  const dynamic_library::name_mangler& mangler
281 
282  void * global_search (const std::string& sym_name);
283 
284  bool is_open (void) const
285  {
286  return (m_search_all_loaded || m_handle != nullptr);
287  }
288 
289  private:
290 
291  HINSTANCE m_handle;
292  };
293 
294  octave_w32_shlib::octave_w32_shlib (const std::string& f)
295  : dynamic_library::dynlib_rep (f), m_handle (nullptr)
296  {
297  if (f.empty())
298  {
299  m_search_all_loaded = true;
300  return;
301  }
302 
303  std::string dir = sys::file_ops::dirname (f);
304  std::wstring wdir = sys::u8_to_wstring (dir);
305  SetDllDirectoryW (dir.empty ()
306  ? nullptr : wdir.c_str ());
307 
308  std::wstring wfile = sys::u8_to_wstring (m_file);
309  m_handle = LoadLibraryW (wfile.c_str ());
310 
311  SetDllDirectoryW (nullptr);
312 
313  if (! m_handle)
314  {
315  DWORD last_error = GetLastError ();
316 
317  wchar_t *error_text = nullptr;
318  FormatMessageW (FORMAT_MESSAGE_FROM_SYSTEM |
319  FORMAT_MESSAGE_ALLOCATE_BUFFER |
320  FORMAT_MESSAGE_IGNORE_INSERTS,
321  nullptr, last_error,
322  MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT),
323  reinterpret_cast <wchar_t *> (&error_text), 0, nullptr);
324 
325  std::ostringstream err_str;
326  err_str << "opening the library '" << m_file << "' failed (error "
327  << last_error << "): ";
328  if (error_text != nullptr)
329  {
330  err_str << sys::u8_from_wstring (error_text);
331  LocalFree (error_text);
332  }
333  else
334  err_str << "Unknown error.";
335 
336  (*current_liboctave_error_handler) ("%s", err_str.str ().c_str ());
337  }
338  }
339 
340  octave_w32_shlib::~octave_w32_shlib (void)
341  {
342  if (m_handle)
343  FreeLibrary (m_handle);
344  }
345 
346  void *
347  octave_w32_shlib::global_search (const std::string& sym_name)
348  {
349  void *function = nullptr;
350 
351  HANDLE proc = GetCurrentProcess ();
352 
353  if (! proc)
354  (*current_liboctave_error_handler)
355  ("Unable to get handle to own process.");
356 
357  size_t lib_num = 64;
358  size_t size_lib = sizeof (HMODULE);
359  HMODULE *h_libs;
360  DWORD bytes_all_libs;
361  bool got_libs;
362 
363  // Get a list of all the libraries in own process.
364  h_libs = static_cast<HMODULE *> (malloc (size_lib*lib_num));
365  got_libs = EnumProcessModules (proc, h_libs, size_lib*lib_num,
366  &bytes_all_libs);
367  int ii = 0;
368  while (((size_lib*lib_num) < bytes_all_libs) && ii++ < 3)
369  {
370  lib_num = bytes_all_libs / size_lib;
371  h_libs = static_cast<HMODULE *> (realloc (h_libs, bytes_all_libs));
372  got_libs = EnumProcessModules (proc, h_libs, bytes_all_libs,
373  &bytes_all_libs);
374  }
375 
376  if (got_libs)
377  {
378  for (size_t i = 0; i < (bytes_all_libs / size_lib); i++)
379  {
380  // Check for function in library.
381  function = reinterpret_cast<void *>
382  (GetProcAddress (h_libs[i], sym_name.c_str ()));
383 
384  if (function)
385  break;
386  }
387  }
388 
389  // Release the handle to the process.
390  CloseHandle (proc);
391 
392  return function;
393  }
394 
395  void *
396  octave_w32_shlib::search (const std::string& name,
397  const dynamic_library::name_mangler& mangler)
398  {
399  void *function = nullptr;
400 
401  if (! m_search_all_loaded && ! is_open ())
402  (*current_liboctave_error_handler)
403  ("shared library %s is not open", m_file.c_str ());
404 
405  std::string sym_name = name;
406 
407  if (mangler)
408  sym_name = mangler (name);
409 
410  if (m_search_all_loaded)
411  function = global_search (sym_name);
412  else
413  function = reinterpret_cast<void *> (GetProcAddress (m_handle,
414  sym_name.c_str ()));
415 
416  return function;
417  }
418 
419 #endif
420 
421  dynamic_library::dynlib_rep *
423  {
424 #if defined (HAVE_DLOPEN_API)
425  return new octave_dlopen_shlib (f);
426 #elif defined (HAVE_LOADLIBRARY_API)
427  return new octave_w32_shlib (f);
428 #else
429  (*current_liboctave_error_handler)
430  ("support for dynamically loaded libraries was unavailable or disabled when liboctave was built");
431 #endif
432  }
433 }
Array< octave_idx_type > find(octave_idx_type n=-1, bool backward=false) const
Find indices of (at most n) nonzero elements.
Definition: Array.cc:2225
bool remove_fcn_name(const std::string &)
Definition: oct-shlib.cc:137
static std::map< std::string, dynlib_rep * > s_instances
Definition: oct-shlib.h:107
std::list< std::string > function_names(void) const
Definition: oct-shlib.cc:115
static dynlib_rep * new_instance(const std::string &f)
Definition: oct-shlib.cc:422
void add_fcn_name(const std::string &)
Definition: oct-shlib.cc:126
static dynlib_rep * get_instance(const std::string &f, bool fake)
Definition: oct-shlib.cc:97
std::function< std::string(const std::string &)> name_mangler
Definition: oct-shlib.h:47
static dynlib_rep s_nil_rep
Definition: oct-shlib.h:121
void * search(const std::string &nm, const name_mangler &mangler=name_mangler()) const
Definition: oct-shlib.h:175
dynamic_library & operator=(const dynamic_library &sl)
Definition: oct-shlib.h:142
sys::time mtime(void) const
Definition: file-stat.h:131
bool is_newer(const sys::time &time) const
Definition: file-stat.h:152
QString name
static std::list< std::string > search(const std::string &path, const std::string &original_name, bool all)
Definition: kpse.cc:486
OCTAVE_NORETURN liboctave_error_handler current_liboctave_error_handler
Definition: lo-error.c:41
std::string dirname(const std::string &path)
Definition: file-ops.cc:363
std::string u8_from_wstring(const std::wstring &wchar_string)
Definition: lo-sysdep.cc:490
std::wstring u8_to_wstring(const std::string &utf8_string)
Definition: lo-sysdep.cc:468
static double f(double k, double l_nu, double c_pm)
Definition: randpoisson.cc:118
void * malloc(unsigned)
octave_value::octave_value(const Array< char > &chm, char type) return retval
Definition: ov.cc:811