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