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