2 #include "mono/metadata/assembly-internals.h"
3 #include "mono/metadata/class-internals.h"
4 #include "mono/metadata/icall-decl.h"
5 #include "mono/metadata/loader-internals.h"
6 #include "mono/metadata/loader.h"
7 #include "mono/metadata/object-internals.h"
8 #include "mono/metadata/reflection-internals.h"
9 #include "mono/utils/checked-build.h"
10 #include "mono/utils/mono-compiler.h"
11 #include "mono/utils/mono-logger-internals.h"
12 #include "mono/utils/mono-path.h"
15 static int pinvoke_search_directories_count
;
16 static char **pinvoke_search_directories
;
18 // In DllImportSearchPath enum, bit 0x2 represents AssemblyDirectory. It is not passed on and is instead handled by the runtime.
19 #define DLLIMPORTSEARCHPATH_ASSEMBLYDIRECTORY 0x2
21 // This lock may be taken within an ALC lock, and should never be the other way around.
22 static MonoCoopMutex native_library_module_lock
;
23 static GHashTable
*native_library_module_map
;
25 * This blacklist is used as a set for cache invalidation purposes with netcore pinvokes.
26 * When pinvokes are resolved with anything other than the last-chance managed event,
27 * the results of that lookup are added to an ALC-level cache. However, if a library is then
28 * unloaded with NativeLibrary.Free(), this cache should be invalidated so that a newly called
29 * pinvoke will not attempt to use it, hence the blacklist. This design means that if another
30 * library is loaded at the same address, it will function with a perf hit, as the entry will
31 * repeatedly be added and removed from the cache due to its presence in the blacklist.
32 * This is a rare scenario and considered a worthwhile tradeoff.
34 static GHashTable
*native_library_module_blacklist
;
37 #ifndef DISABLE_DLLMAP
38 static MonoDllMap
*global_dll_map
;
41 static GHashTable
*global_module_map
; // should only be accessed with the global loader data lock
43 static MonoDl
*internal_module
; // used when pinvoking `__Internal`
45 // Did we initialize the temporary directory for dynamic libraries
46 // FIXME: this is racy
47 static gboolean bundle_save_library_initialized
;
49 // List of bundled libraries we unpacked
50 static GSList
*bundle_library_paths
;
52 // Directory where we unpacked dynamic libraries
53 static char *bundled_dylibrary_directory
;
56 LOOKUP_PINVOKE_ERR_OK
= 0, /* No error */
57 LOOKUP_PINVOKE_ERR_NO_LIB
, /* DllNotFoundException */
58 LOOKUP_PINVOKE_ERR_NO_SYM
, /* EntryPointNotFoundException */
59 } MonoLookupPInvokeErr
;
61 /* We should just use a MonoError, but mono_lookup_pinvoke_call has this legacy
62 * error reporting mechanism where it returns an exception class and a string
63 * message. So instead we return an error code and message, and for internal
64 * callers convert it to a MonoError.
66 * Don't expose this type to the runtime. It's just an implementation
67 * detail for backward compatability.
69 typedef struct MonoLookupPInvokeStatus
{
70 MonoLookupPInvokeErr err_code
;
72 } MonoLookupPInvokeStatus
;
74 /* Class lazy loading functions */
75 GENERATE_GET_CLASS_WITH_CACHE (appdomain_unloaded_exception
, "System", "AppDomainUnloadedException")
76 GENERATE_TRY_GET_CLASS_WITH_CACHE (appdomain_unloaded_exception
, "System", "AppDomainUnloadedException")
78 GENERATE_GET_CLASS_WITH_CACHE (native_library
, "System.Runtime.InteropServices", "NativeLibrary");
81 #ifndef DISABLE_DLLMAP
83 * LOCKING: Assumes the relevant lock is held.
84 * For the global DllMap, this is `global_loader_data_mutex`, and for images it's their internal lock.
87 mono_dllmap_lookup_list (MonoDllMap
*dll_map
, const char *dll
, const char* func
, const char **rdll
, const char **rfunc
) {
88 gboolean found
= FALSE
;
97 * we use the first entry we find that matches, since entries from
98 * the config file are prepended to the list and we document that the
101 for (; dll_map
; dll_map
= dll_map
->next
) {
102 // Check case-insensitively when the dll name is prefixed with 'i:'
103 gboolean case_insensitive_match
= strncmp (dll_map
->dll
, "i:", 2) == 0 && g_ascii_strcasecmp (dll_map
->dll
+ 2, dll
) == 0;
104 gboolean case_sensitive_match
= strcmp (dll_map
->dll
, dll
) == 0;
105 if (!(case_insensitive_match
|| case_sensitive_match
))
108 if (!found
&& dll_map
->target
) {
109 *rdll
= dll_map
->target
;
111 /* we don't quit here, because we could find a full
112 * entry that also matches the function, which takes priority.
115 if (dll_map
->func
&& strcmp (dll_map
->func
, func
) == 0) {
116 *rdll
= dll_map
->target
;
117 *rfunc
= dll_map
->target_func
;
127 * The locking and GC state transitions here are wonky due to the fact the image lock is a coop lock
128 * and the global loader data lock is an OS lock.
131 mono_dllmap_lookup (MonoImage
*assembly
, const char *dll
, const char* func
, const char **rdll
, const char **rfunc
)
135 MONO_REQ_GC_UNSAFE_MODE
;
137 if (assembly
&& assembly
->dll_map
) {
138 mono_image_lock (assembly
);
139 res
= mono_dllmap_lookup_list (assembly
->dll_map
, dll
, func
, rdll
, rfunc
);
140 mono_image_unlock (assembly
);
147 mono_global_loader_data_lock ();
148 res
= mono_dllmap_lookup_list (global_dll_map
, dll
, func
, rdll
, rfunc
);
149 mono_global_loader_data_unlock ();
154 *rdll
= g_strdup (*rdll
);
155 *rfunc
= g_strdup (*rfunc
);
161 dllmap_insert_global (const char *dll
, const char *func
, const char *tdll
, const char *tfunc
)
165 entry
= (MonoDllMap
*)g_malloc0 (sizeof (MonoDllMap
));
166 entry
->dll
= dll
? g_strdup (dll
): NULL
;
167 entry
->target
= tdll
? g_strdup (tdll
): NULL
;
168 entry
->func
= func
? g_strdup (func
): NULL
;
169 entry
->target_func
= tfunc
? g_strdup (tfunc
): (func
? g_strdup (func
): NULL
);
171 // No transition here because this is early in startup
172 mono_global_loader_data_lock ();
173 entry
->next
= global_dll_map
;
174 global_dll_map
= entry
;
175 mono_global_loader_data_unlock ();
180 dllmap_insert_image (MonoImage
*assembly
, const char *dll
, const char *func
, const char *tdll
, const char *tfunc
)
183 g_assert (assembly
!= NULL
);
185 MONO_REQ_GC_UNSAFE_MODE
;
187 entry
= (MonoDllMap
*)mono_image_alloc0 (assembly
, sizeof (MonoDllMap
));
188 entry
->dll
= dll
? mono_image_strdup (assembly
, dll
): NULL
;
189 entry
->target
= tdll
? mono_image_strdup (assembly
, tdll
): NULL
;
190 entry
->func
= func
? mono_image_strdup (assembly
, func
): NULL
;
191 entry
->target_func
= tfunc
? mono_image_strdup (assembly
, tfunc
): (func
? mono_image_strdup (assembly
, func
): NULL
);
193 mono_image_lock (assembly
);
194 entry
->next
= assembly
->dll_map
;
195 assembly
->dll_map
= entry
;
196 mono_image_unlock (assembly
);
200 * LOCKING: Assumes the relevant lock is held.
201 * For the global DllMap, this is `global_loader_data_mutex`, and for images it's their internal lock.
204 free_dllmap (MonoDllMap
*map
)
207 MonoDllMap
*next
= map
->next
;
210 g_free (map
->target
);
212 g_free (map
->target_func
);
219 mono_dllmap_insert_internal (MonoImage
*assembly
, const char *dll
, const char *func
, const char *tdll
, const char *tfunc
)
222 // The locking in here is _really_ wonky, and I'm not convinced this function should exist.
223 // I've split it into an internal version to offer flexibility in the future.
225 dllmap_insert_global (dll
, func
, tdll
, tfunc
);
227 dllmap_insert_image (assembly
, dll
, func
, tdll
, tfunc
);
231 mono_global_dllmap_cleanup (void)
233 // No need for a transition here since the thread is already detached from the runtime
234 mono_global_loader_data_lock ();
236 free_dllmap (global_dll_map
);
237 global_dll_map
= NULL
;
239 // We don't care about freeing native_library_module_map on netcore because of the expedited shutdown.
241 mono_global_loader_data_unlock ();
246 * mono_dllmap_insert:
247 * \param assembly if NULL, this is a global mapping, otherwise the remapping of the dynamic library will only apply to the specified assembly
248 * \param dll The name of the external library, as it would be found in the \c DllImport declaration. If prefixed with <code>i:</code> the matching of the library name is done without case sensitivity
249 * \param func if not null, the mapping will only applied to the named function (the value of <code>EntryPoint</code>)
250 * \param tdll The name of the library to map the specified \p dll if it matches.
251 * \param tfunc The name of the function that replaces the invocation. If NULL, it is replaced with a copy of \p func.
253 * LOCKING: Acquires the image lock, or the loader data lock if an image is not passed.
255 * This function is used to programatically add \c DllImport remapping in either
256 * a specific assembly, or as a global remapping. This is done by remapping
257 * references in a \c DllImport attribute from the \p dll library name into the \p tdll
258 * name. If the \p dll name contains the prefix <code>i:</code>, the comparison of the
259 * library name is done without case sensitivity.
261 * If you pass \p func, this is the name of the \c EntryPoint in a \c DllImport if specified
262 * or the name of the function as determined by \c DllImport. If you pass \p func, you
263 * must also pass \p tfunc which is the name of the target function to invoke on a match.
267 * <code>mono_dllmap_insert (NULL, "i:libdemo.dll", NULL, relocated_demo_path, NULL);</code>
269 * The above will remap \c DllImport statements for \c libdemo.dll and \c LIBDEMO.DLL to
270 * the contents of \c relocated_demo_path for all assemblies in the Mono process.
272 * NOTE: This can be called before the runtime is initialized, for example from
273 * \c mono_config_parse.
276 mono_dllmap_insert (MonoImage
*assembly
, const char *dll
, const char *func
, const char *tdll
, const char *tfunc
)
278 #ifndef DISABLE_DLLMAP
279 mono_dllmap_insert_internal (assembly
, dll
, func
, tdll
, tfunc
);
284 mono_loader_register_module (const char *name
, MonoDl
*module
)
288 // No transition here because this is early in startup
289 mono_global_loader_data_lock ();
291 g_hash_table_insert (global_module_map
, g_strdup (name
), module
);
293 mono_global_loader_data_unlock ();
296 #ifdef ENABLE_NETCORE
298 mono_loader_register_module_locking (const char *name
, MonoDl
*module
)
300 MonoDl
*result
= NULL
;
303 mono_global_loader_data_lock ();
306 result
= (MonoDl
*)g_hash_table_lookup (global_module_map
, name
);
308 g_free (module
->full_name
);
313 g_hash_table_insert (global_module_map
, g_strdup (name
), module
);
318 mono_global_loader_data_unlock ();
326 remove_cached_module (gpointer key
, gpointer value
, gpointer user_data
)
328 mono_dl_close((MonoDl
*)value
);
332 mono_global_loader_cache_init (void)
334 if (!global_module_map
)
335 global_module_map
= g_hash_table_new (g_str_hash
, g_str_equal
);
337 #ifdef ENABLE_NETCORE
338 if (!native_library_module_map
)
339 native_library_module_map
= g_hash_table_new (g_direct_hash
, g_direct_equal
);
340 if (!native_library_module_blacklist
)
341 native_library_module_blacklist
= g_hash_table_new (g_direct_hash
, g_direct_equal
);
342 mono_coop_mutex_init (&native_library_module_lock
);
347 mono_global_loader_cache_cleanup (void)
349 if (global_module_map
!= NULL
) {
350 g_hash_table_foreach(global_module_map
, remove_cached_module
, NULL
);
352 g_hash_table_destroy(global_module_map
);
353 global_module_map
= NULL
;
356 // No need to clean up the native library hash tables since they're netcore-only, where this is never called
360 is_absolute_path (const char *path
)
362 // FIXME: other platforms have similar prefixes, such as $ORIGIN
364 if (!strncmp (path
, "@executable_path/", 17) || !strncmp (path
, "@loader_path/", 13) || !strncmp (path
, "@rpath/", 7))
367 return g_path_is_absolute (path
);
371 lookup_pinvoke_call_impl (MonoMethod
*method
, MonoLookupPInvokeStatus
*status_out
);
374 pinvoke_probe_for_symbol (MonoDl
*module
, MonoMethodPInvoke
*piinfo
, const char *import
, char **error_msg_out
);
377 pinvoke_probe_convert_status_for_api (MonoLookupPInvokeStatus
*status
, const char **exc_class
, const char **exc_arg
)
381 switch (status
->err_code
) {
382 case LOOKUP_PINVOKE_ERR_OK
:
386 case LOOKUP_PINVOKE_ERR_NO_LIB
:
387 *exc_class
= "DllNotFoundException";
388 *exc_arg
= status
->err_arg
;
389 status
->err_arg
= NULL
;
391 case LOOKUP_PINVOKE_ERR_NO_SYM
:
392 *exc_class
= "EntryPointNotFoundException";
393 *exc_arg
= status
->err_arg
;
394 status
->err_arg
= NULL
;
397 g_assert_not_reached ();
402 pinvoke_probe_convert_status_to_error (MonoLookupPInvokeStatus
*status
, MonoError
*error
)
404 /* Note: this has to return a MONO_ERROR_GENERIC because mono_mb_emit_exception_for_error only knows how to decode generic errors. */
405 switch (status
->err_code
) {
406 case LOOKUP_PINVOKE_ERR_OK
:
408 case LOOKUP_PINVOKE_ERR_NO_LIB
:
409 mono_error_set_generic_error (error
, "System", "DllNotFoundException", "%s", status
->err_arg
);
410 g_free (status
->err_arg
);
411 status
->err_arg
= NULL
;
413 case LOOKUP_PINVOKE_ERR_NO_SYM
:
414 mono_error_set_generic_error (error
, "System", "EntryPointNotFoundException", "%s", status
->err_arg
);
415 g_free (status
->err_arg
);
416 status
->err_arg
= NULL
;
419 g_assert_not_reached ();
424 * mono_lookup_pinvoke_call:
427 mono_lookup_pinvoke_call (MonoMethod
*method
, const char **exc_class
, const char **exc_arg
)
430 MONO_ENTER_GC_UNSAFE
;
431 MonoLookupPInvokeStatus status
;
432 memset (&status
, 0, sizeof (status
));
433 result
= lookup_pinvoke_call_impl (method
, &status
);
434 pinvoke_probe_convert_status_for_api (&status
, exc_class
, exc_arg
);
440 mono_lookup_pinvoke_call_internal (MonoMethod
*method
, MonoError
*error
)
443 MonoLookupPInvokeStatus status
;
444 memset (&status
, 0, sizeof (status
));
445 result
= lookup_pinvoke_call_impl (method
, &status
);
447 pinvoke_probe_convert_status_to_error (&status
, error
);
451 #ifdef ENABLE_NETCORE
453 mono_set_pinvoke_search_directories (int dir_count
, char **dirs
)
455 pinvoke_search_directories_count
= dir_count
;
456 pinvoke_search_directories
= dirs
;
460 native_library_lock (void)
462 mono_coop_mutex_lock (&native_library_module_lock
);
466 native_library_unlock (void)
468 mono_coop_mutex_unlock (&native_library_module_lock
);
472 alc_pinvoke_lock (MonoAssemblyLoadContext
*alc
)
474 mono_coop_mutex_lock (&alc
->pinvoke_lock
);
478 alc_pinvoke_unlock (MonoAssemblyLoadContext
*alc
)
480 mono_coop_mutex_unlock (&alc
->pinvoke_lock
);
483 // LOCKING: expects you to hold native_library_module_lock
485 netcore_handle_lookup (gpointer handle
)
487 return (MonoDl
*)g_hash_table_lookup (native_library_module_map
, handle
);
490 // LOCKING: expects you to hold native_library_module_lock
492 netcore_check_blacklist (MonoDl
*module
)
494 return g_hash_table_contains (native_library_module_blacklist
, module
);
498 netcore_probe_for_module_variations (const char *mdirname
, const char *file_name
)
502 MonoDl
*module
= NULL
;
504 // This does not actually mirror CoreCLR's algorithm; if that becomes a problem, potentially use theirs
505 // FIXME: this appears to search *.dylib twice for some reason
506 while ((full_name
= mono_dl_build_path (mdirname
, file_name
, &iter
)) && module
== NULL
) {
508 module
= mono_dl_open (full_name
, MONO_DL_LAZY
, &error_msg
);
510 mono_trace (G_LOG_LEVEL_INFO
, MONO_TRACE_DLLIMPORT
, "DllImport error loading library '%s': '%s'.", full_name
, error_msg
);
521 netcore_probe_for_module (MonoImage
*image
, const char *file_name
, int flags
)
523 MonoDl
*module
= NULL
;
524 gboolean search_assembly_dir
= flags
& DLLIMPORTSEARCHPATH_ASSEMBLYDIRECTORY
;
526 // Try without any path additions
527 module
= netcore_probe_for_module_variations (NULL
, file_name
);
529 // Check the NATIVE_DLL_SEARCH_DIRECTORIES
530 for (int i
= 0; i
< pinvoke_search_directories_count
&& module
== NULL
; ++i
)
531 module
= netcore_probe_for_module_variations (pinvoke_search_directories
[i
], file_name
);
533 // Check the assembly directory if the search flag is set and the image exists
534 if (search_assembly_dir
&& image
!= NULL
&& module
== NULL
) {
535 char *mdirname
= g_path_get_dirname (image
->filename
);
537 module
= netcore_probe_for_module_variations (mdirname
, file_name
);
545 netcore_resolve_with_dll_import_resolver (MonoAssemblyLoadContext
*alc
, MonoAssembly
*assembly
, const char *scope
, guint32 flags
, MonoError
*error
)
547 MonoDl
*result
= NULL
;
549 MonoDomain
*domain
= mono_alc_domain (alc
);
551 MONO_STATIC_POINTER_INIT (MonoMethod
, resolve
)
553 ERROR_DECL (local_error
);
554 MonoClass
*native_lib_class
= mono_class_get_native_library_class ();
555 g_assert (native_lib_class
);
556 resolve
= mono_class_get_method_from_name_checked (native_lib_class
, "MonoLoadLibraryCallbackStub", -1, 0, local_error
);
557 mono_error_assert_ok (local_error
);
559 MONO_STATIC_POINTER_INIT_END (MonoMethod
, resolve
)
562 if (mono_runtime_get_no_exec ())
565 HANDLE_FUNCTION_ENTER ();
567 MonoStringHandle scope_handle
= mono_string_new_handle (domain
, scope
, error
);
568 goto_if_nok (error
, leave
);
569 MonoReflectionAssemblyHandle assembly_handle
= mono_assembly_get_object_handle (domain
, assembly
, error
);
570 goto_if_nok (error
, leave
);
572 gboolean has_search_flags
= flags
!= 0 ? TRUE
: FALSE
;
574 args
[0] = MONO_HANDLE_RAW (scope_handle
);
575 args
[1] = MONO_HANDLE_RAW (assembly_handle
);
576 args
[2] = &has_search_flags
;
579 mono_runtime_invoke_checked (resolve
, NULL
, args
, error
);
580 goto_if_nok (error
, leave
);
582 native_library_lock ();
583 result
= netcore_handle_lookup (lib
);
584 native_library_unlock ();
587 HANDLE_FUNCTION_RETURN_VAL (result
);
591 netcore_resolve_with_dll_import_resolver_nofail (MonoAssemblyLoadContext
*alc
, MonoAssembly
*assembly
, const char *scope
, guint32 flags
)
593 MonoDl
*result
= NULL
;
596 result
= netcore_resolve_with_dll_import_resolver (alc
, assembly
, scope
, flags
, error
);
598 mono_trace (G_LOG_LEVEL_INFO
, MONO_TRACE_ASSEMBLY
, "Error while invoking ALC DllImportResolver(\"%s\") delegate: '%s'", scope
, mono_error_get_message (error
));
600 mono_error_cleanup (error
);
606 netcore_resolve_with_load (MonoAssemblyLoadContext
*alc
, const char *scope
, MonoError
*error
)
608 MonoDl
*result
= NULL
;
611 MONO_STATIC_POINTER_INIT (MonoMethod
, resolve
)
613 ERROR_DECL (local_error
);
614 MonoClass
*alc_class
= mono_class_get_assembly_load_context_class ();
615 g_assert (alc_class
);
616 resolve
= mono_class_get_method_from_name_checked (alc_class
, "MonoResolveUnmanagedDll", -1, 0, local_error
);
617 mono_error_assert_ok (local_error
);
619 MONO_STATIC_POINTER_INIT_END (MonoMethod
, resolve
)
622 if (mono_runtime_get_no_exec ())
625 HANDLE_FUNCTION_ENTER ();
627 MonoStringHandle scope_handle
= mono_string_new_handle (mono_alc_domain (alc
), scope
, error
);
628 goto_if_nok (error
, leave
);
630 gpointer gchandle
= GUINT_TO_POINTER (alc
->gchandle
);
632 args
[0] = MONO_HANDLE_RAW (scope_handle
);
633 args
[1] = &gchandle
;
635 mono_runtime_invoke_checked (resolve
, NULL
, args
, error
);
636 goto_if_nok (error
, leave
);
638 native_library_lock ();
639 result
= netcore_handle_lookup (lib
);
640 native_library_unlock ();
643 HANDLE_FUNCTION_RETURN_VAL (result
);
647 netcore_resolve_with_load_nofail (MonoAssemblyLoadContext
*alc
, const char *scope
)
649 MonoDl
*result
= NULL
;
652 result
= netcore_resolve_with_load (alc
, scope
, error
);
654 mono_trace (G_LOG_LEVEL_INFO
, MONO_TRACE_ASSEMBLY
, "Error while invoking ALC LoadUnmanagedDll(\"%s\") method: '%s'", scope
, mono_error_get_message (error
));
656 mono_error_cleanup (error
);
662 netcore_resolve_with_resolving_event (MonoAssemblyLoadContext
*alc
, MonoAssembly
*assembly
, const char *scope
, MonoError
*error
)
664 MonoDl
*result
= NULL
;
666 MonoDomain
*domain
= mono_alc_domain (alc
);
668 MONO_STATIC_POINTER_INIT (MonoMethod
, resolve
)
670 ERROR_DECL (local_error
);
671 MonoClass
*alc_class
= mono_class_get_assembly_load_context_class ();
672 g_assert (alc_class
);
673 resolve
= mono_class_get_method_from_name_checked (alc_class
, "MonoResolveUnmanagedDllUsingEvent", -1, 0, local_error
);
674 mono_error_assert_ok (local_error
);
676 MONO_STATIC_POINTER_INIT_END (MonoMethod
, resolve
)
679 if (mono_runtime_get_no_exec ())
682 HANDLE_FUNCTION_ENTER ();
684 MonoStringHandle scope_handle
= mono_string_new_handle (domain
, scope
, error
);
685 goto_if_nok (error
, leave
);
686 MonoReflectionAssemblyHandle assembly_handle
= mono_assembly_get_object_handle (domain
, assembly
, error
);
687 goto_if_nok (error
, leave
);
689 gpointer gchandle
= GUINT_TO_POINTER (alc
->gchandle
);
691 args
[0] = MONO_HANDLE_RAW (scope_handle
);
692 args
[1] = MONO_HANDLE_RAW (assembly_handle
);
693 args
[2] = &gchandle
;
695 mono_runtime_invoke_checked (resolve
, NULL
, args
, error
);
696 goto_if_nok (error
, leave
);
698 native_library_lock ();
699 result
= netcore_handle_lookup (lib
);
700 native_library_unlock ();
703 HANDLE_FUNCTION_RETURN_VAL (result
);
707 netcore_resolve_with_resolving_event_nofail (MonoAssemblyLoadContext
*alc
, MonoAssembly
*assembly
, const char *scope
)
709 MonoDl
*result
= NULL
;
712 result
= netcore_resolve_with_resolving_event (alc
, assembly
, scope
, error
);
714 mono_trace (G_LOG_LEVEL_INFO
, MONO_TRACE_ASSEMBLY
, "Error while invoking ALC ResolvingUnmangedDll(\"%s\") event: '%s'", scope
, mono_error_get_message (error
));
716 mono_error_cleanup (error
);
721 // LOCKING: expects you to hold the ALC's pinvoke lock
723 netcore_check_alc_cache (MonoAssemblyLoadContext
*alc
, const char *scope
)
725 MonoDl
*result
= NULL
;
727 result
= (MonoDl
*)g_hash_table_lookup (alc
->pinvoke_scopes
, scope
);
730 gboolean blacklisted
;
732 native_library_lock ();
733 blacklisted
= netcore_check_blacklist (result
);
734 native_library_unlock ();
737 g_hash_table_remove (alc
->pinvoke_scopes
, scope
);
746 netcore_lookup_native_library (MonoAssemblyLoadContext
*alc
, MonoImage
*image
, const char *scope
, guint32 flags
)
748 MonoDl
*module
= NULL
;
750 MonoAssembly
*assembly
= mono_image_get_assembly (image
);
751 char *error_msg
= NULL
;
753 MONO_REQ_GC_UNSAFE_MODE
;
755 mono_trace (G_LOG_LEVEL_INFO
, MONO_TRACE_DLLIMPORT
, "DllImport attempting to load: '%s'.", scope
);
757 // We allow a special name to dlopen from the running process namespace, which is not present in CoreCLR
758 if (strcmp (scope
, "__Internal") == 0) {
759 if (!internal_module
)
760 internal_module
= mono_dl_open (NULL
, MONO_DL_LAZY
, &error_msg
);
761 module
= internal_module
;
764 mono_trace (G_LOG_LEVEL_INFO
, MONO_TRACE_DLLIMPORT
, "DllImport error loading library '__Internal': '%s'.", error_msg
);
772 * Try these until one of them succeeds:
774 * 1. Check the cache in the active ALC.
776 * 2. Call the DllImportResolver on the active assembly.
778 * 3. Call LoadUnmanagedDll on the active ALC.
780 * 4. Check the global cache.
782 * 5. Run the unmanaged probing logic.
784 * 6. Raise the ResolvingUnmanagedDll event on the active ALC.
789 alc_pinvoke_lock (alc
);
790 module
= netcore_check_alc_cache (alc
, scope
);
791 alc_pinvoke_unlock (alc
);
795 module
= (MonoDl
*)netcore_resolve_with_dll_import_resolver_nofail (alc
, assembly
, scope
, flags
);
797 goto add_to_alc_cache
;
799 module
= (MonoDl
*)netcore_resolve_with_load_nofail (alc
, scope
);
801 goto add_to_alc_cache
;
804 mono_global_loader_data_lock ();
806 module
= (MonoDl
*)g_hash_table_lookup (global_module_map
, scope
);
808 mono_global_loader_data_unlock ();
811 goto add_to_alc_cache
;
813 module
= netcore_probe_for_module (image
, scope
, flags
);
815 goto add_to_global_cache
;
817 /* As this is last chance, I've opted not to put it in a cache, but that is not necessarily the correct decision.
818 * It is rather convenient here, however, because it means the global cache will only be populated by libraries
819 * resolved via netcore_probe_for_module and not NativeLibrary, eliminating potential races/conflicts.
821 module
= netcore_resolve_with_resolving_event_nofail (alc
, assembly
, scope
);
825 module
= mono_loader_register_module_locking (scope
, module
);
828 /* Nothing is closed here because the only two places this can come from are:
829 * 1. A managed callback that made use of NativeLibrary.Load, in which case closing is dependent on NativeLibrary.Free
830 * 2. The global cache, which is only populated by results of netcore_probe_for_module. When adding to the global cache,
831 * we free the new MonoDl if another thread beat us, so we don't have to repeat that here.
833 alc_pinvoke_lock (alc
);
834 cached
= netcore_check_alc_cache (alc
, scope
);
838 g_hash_table_insert (alc
->pinvoke_scopes
, g_strdup (scope
), module
);
839 alc_pinvoke_unlock (alc
);
845 #else // ENABLE_NETCORE
848 cached_module_load (const char *name
, int flags
, char **err
)
856 mono_global_loader_data_lock ();
859 res
= (MonoDl
*)g_hash_table_lookup (global_module_map
, name
);
863 res
= mono_dl_open (name
, flags
, err
);
865 g_hash_table_insert (global_module_map
, g_strdup (name
), res
);
869 mono_global_loader_data_unlock ();
876 * legacy_probe_transform_path:
878 * Try transforming the library path given in \p new_scope in different ways
879 * depending on \p phase
881 * \returns \c TRUE if a transformation was applied and the transformed path
882 * components are written to the out arguments, or \c FALSE if a transformation
886 legacy_probe_transform_path (const char *new_scope
, int phase
, char **file_name_out
, char **base_name_out
, char **dir_name_out
, gboolean
*is_absolute_out
)
888 char *file_name
= NULL
, *base_name
= NULL
, *dir_name
= NULL
;
889 gboolean changed
= FALSE
;
890 gboolean is_absolute
= is_absolute_path (new_scope
);
893 /* Try the original name */
894 file_name
= g_strdup (new_scope
);
898 /* Try trimming the .dll extension */
899 if (strstr (new_scope
, ".dll") == (new_scope
+ strlen (new_scope
) - 4)) {
900 file_name
= g_strdup (new_scope
);
901 file_name
[strlen (new_scope
) - 4] = '\0';
907 dir_name
= g_path_get_dirname (new_scope
);
908 base_name
= g_path_get_basename (new_scope
);
909 if (strstr (base_name
, "lib") != base_name
) {
910 char *tmp
= g_strdup_printf ("lib%s", base_name
);
913 file_name
= g_strdup_printf ("%s%s%s", dir_name
, G_DIR_SEPARATOR_S
, base_name
);
916 } else if (strstr (new_scope
, "lib") != new_scope
) {
917 file_name
= g_strdup_printf ("lib%s", new_scope
);
922 if (!is_absolute
&& mono_dl_get_system_dir ()) {
923 dir_name
= (char*)mono_dl_get_system_dir ();
924 file_name
= g_path_get_basename (new_scope
);
931 if (!g_ascii_strcasecmp ("user32.dll", new_scope
) ||
932 !g_ascii_strcasecmp ("kernel32.dll", new_scope
) ||
933 !g_ascii_strcasecmp ("user32", new_scope
) ||
934 !g_ascii_strcasecmp ("kernel", new_scope
)) {
935 file_name
= g_strdup ("libMonoSupportW.so");
941 if (changed
&& is_absolute
) {
943 dir_name
= g_path_get_dirname (file_name
);
945 base_name
= g_path_get_basename (file_name
);
947 *file_name_out
= file_name
;
948 *base_name_out
= base_name
;
949 *dir_name_out
= dir_name
;
950 *is_absolute_out
= is_absolute
;
955 legacy_probe_for_module_in_directory (const char *mdirname
, const char *file_name
)
959 MonoDl
* module
= NULL
;
961 while ((full_name
= mono_dl_build_path (mdirname
, file_name
, &iter
)) && module
== NULL
) {
963 module
= cached_module_load (full_name
, MONO_DL_LAZY
, &error_msg
);
965 mono_trace (G_LOG_LEVEL_INFO
, MONO_TRACE_DLLIMPORT
, "DllImport error loading library '%s': '%s'.", full_name
, error_msg
);
976 legacy_probe_for_module_relative_directories (MonoImage
*image
, const char *file_name
)
978 MonoDl
* module
= NULL
;
980 for (int j
= 0; j
< 3; ++j
) {
981 char *mdirname
= NULL
;
985 mdirname
= g_path_get_dirname (image
->filename
);
987 case 1: // @executable_path@/../lib
989 char buf
[4096]; // FIXME: MAX_PATH
991 binl
= mono_dl_get_executable_path (buf
, sizeof (buf
));
993 char *base
, *newbase
;
996 resolvedname
= mono_path_resolve_symlinks (buf
);
998 base
= g_path_get_dirname (resolvedname
);
999 newbase
= g_path_get_dirname(base
);
1001 // On Android the executable for the application is going to be /system/bin/app_process{32,64} depending on
1002 // the application's architecture. However, libraries for the different architectures live in different
1003 // subdirectories of `/system`: `lib` for 32-bit apps and `lib64` for 64-bit ones. Thus appending `/lib` below
1004 // will fail to load the DSO for a 64-bit app, even if it exists there, because it will have a different
1005 // architecture. This is the cause of https://github.com/xamarin/xamarin-android/issues/2780 and the ifdef
1006 // below is the fix.
1007 mdirname
= g_strdup_printf (
1008 #if defined(TARGET_ANDROID) && (defined(TARGET_ARM64) || defined(TARGET_AMD64))
1014 g_free (resolvedname
);
1021 case 2: // @executable_path@/../Libraries
1023 char buf
[4096]; // FIXME: MAX_PATH
1025 binl
= mono_dl_get_executable_path (buf
, sizeof (buf
));
1027 char *base
, *newbase
;
1030 resolvedname
= mono_path_resolve_symlinks (buf
);
1032 base
= g_path_get_dirname (resolvedname
);
1033 newbase
= g_path_get_dirname(base
);
1034 mdirname
= g_strdup_printf ("%s/Libraries", newbase
);
1036 g_free (resolvedname
);
1048 module
= legacy_probe_for_module_in_directory (mdirname
, file_name
);
1058 legacy_probe_for_module (MonoImage
*image
, const char *new_scope
)
1060 char *full_name
, *file_name
;
1061 char *error_msg
= NULL
;
1063 MonoDl
*module
= NULL
;
1065 mono_trace (G_LOG_LEVEL_INFO
, MONO_TRACE_DLLIMPORT
, "DllImport attempting to load: '%s'.", new_scope
);
1067 /* we allow a special name to dlopen from the running process namespace */
1068 if (strcmp (new_scope
, "__Internal") == 0) {
1069 if (!internal_module
)
1070 internal_module
= mono_dl_open (NULL
, MONO_DL_LAZY
, &error_msg
);
1071 module
= internal_module
;
1074 mono_trace (G_LOG_LEVEL_INFO
, MONO_TRACE_DLLIMPORT
, "DllImport error loading library '__Internal': '%s'.", error_msg
);
1082 * Try loading the module using a variety of names
1084 for (i
= 0; i
< 5; ++i
) {
1085 char *base_name
= NULL
, *dir_name
= NULL
;
1086 gboolean is_absolute
;
1088 gboolean changed
= legacy_probe_transform_path (new_scope
, i
, &file_name
, &base_name
, &dir_name
, &is_absolute
);
1092 if (!module
&& is_absolute
) {
1093 module
= cached_module_load (file_name
, MONO_DL_LAZY
, &error_msg
);
1095 mono_trace (G_LOG_LEVEL_INFO
, MONO_TRACE_DLLIMPORT
,
1096 "DllImport error loading library '%s': '%s'.",
1097 file_name
, error_msg
);
1102 if (!module
&& !is_absolute
) {
1103 module
= legacy_probe_for_module_relative_directories (image
, file_name
);
1108 char *file_or_base
= is_absolute
? base_name
: file_name
;
1109 while ((full_name
= mono_dl_build_path (dir_name
, file_or_base
, &iter
))) {
1110 module
= cached_module_load (full_name
, MONO_DL_LAZY
, &error_msg
);
1112 mono_trace (G_LOG_LEVEL_INFO
, MONO_TRACE_DLLIMPORT
,
1113 "DllImport error loading library '%s': '%s'.",
1114 full_name
, error_msg
);
1124 module
= cached_module_load (file_name
, MONO_DL_LAZY
, &error_msg
);
1126 mono_trace (G_LOG_LEVEL_INFO
, MONO_TRACE_DLLIMPORT
,
1127 "DllImport error loading library '%s': '%s'.",
1128 file_name
, error_msg
);
1147 legacy_lookup_native_library (MonoImage
*image
, const char *scope
)
1149 MonoDl
*module
= NULL
;
1150 gboolean cached
= FALSE
;
1152 mono_image_lock (image
);
1153 if (!image
->pinvoke_scopes
)
1154 image
->pinvoke_scopes
= g_hash_table_new_full (g_str_hash
, g_str_equal
, g_free
, NULL
);
1155 module
= (MonoDl
*)g_hash_table_lookup (image
->pinvoke_scopes
, scope
);
1156 mono_image_unlock (image
);
1161 module
= legacy_probe_for_module (image
, scope
);
1163 if (module
&& !cached
) {
1164 mono_trace (G_LOG_LEVEL_INFO
, MONO_TRACE_DLLIMPORT
,
1165 "DllImport loaded library '%s'.", module
->full_name
);
1166 mono_image_lock (image
);
1167 if (!g_hash_table_lookup (image
->pinvoke_scopes
, scope
)) {
1168 g_hash_table_insert (image
->pinvoke_scopes
, g_strdup (scope
), module
);
1170 mono_image_unlock (image
);
1176 #endif // ENABLE_NETCORE
1179 lookup_pinvoke_call_impl (MonoMethod
*method
, MonoLookupPInvokeStatus
*status_out
)
1181 MonoImage
*image
= m_class_get_image (method
->klass
);
1182 #ifdef ENABLE_NETCORE
1183 MonoAssemblyLoadContext
*alc
= mono_image_get_alc (image
);
1185 MonoMethodPInvoke
*piinfo
= (MonoMethodPInvoke
*)method
;
1186 MonoTableInfo
*tables
= image
->tables
;
1187 MonoTableInfo
*im
= &tables
[MONO_TABLE_IMPLMAP
];
1188 MonoTableInfo
*mr
= &tables
[MONO_TABLE_MODULEREF
];
1189 guint32 im_cols
[MONO_IMPLMAP_SIZE
];
1190 guint32 scope_token
;
1191 const char *orig_import
= NULL
;
1192 const char *new_import
= NULL
;
1193 const char *orig_scope
= NULL
;
1194 const char *new_scope
= NULL
;
1195 char *error_msg
= NULL
;
1196 MonoDl
*module
= NULL
;
1197 gpointer addr
= NULL
;
1199 MONO_REQ_GC_UNSAFE_MODE
;
1201 g_assert (method
->flags
& METHOD_ATTRIBUTE_PINVOKE_IMPL
);
1203 g_assert (status_out
);
1206 return piinfo
->addr
;
1208 if (image_is_dynamic (image
)) {
1209 MonoReflectionMethodAux
*method_aux
=
1210 (MonoReflectionMethodAux
*)g_hash_table_lookup (
1211 ((MonoDynamicImage
*)m_class_get_image (method
->klass
))->method_aux_hash
, method
);
1215 orig_import
= method_aux
->dllentry
;
1216 orig_scope
= method_aux
->dll
;
1219 if (!piinfo
->implmap_idx
|| piinfo
->implmap_idx
> im
->rows
)
1222 mono_metadata_decode_row (im
, piinfo
->implmap_idx
- 1, im_cols
, MONO_IMPLMAP_SIZE
);
1224 if (!im_cols
[MONO_IMPLMAP_SCOPE
] || im_cols
[MONO_IMPLMAP_SCOPE
] > mr
->rows
)
1227 piinfo
->piflags
= im_cols
[MONO_IMPLMAP_FLAGS
];
1228 orig_import
= mono_metadata_string_heap (image
, im_cols
[MONO_IMPLMAP_NAME
]);
1229 scope_token
= mono_metadata_decode_row_col (mr
, im_cols
[MONO_IMPLMAP_SCOPE
] - 1, MONO_MODULEREF_NAME
);
1230 orig_scope
= mono_metadata_string_heap (image
, scope_token
);
1233 #ifndef DISABLE_DLLMAP
1234 // FIXME: The dllmap remaps System.Native to mono-native
1235 mono_dllmap_lookup (image
, orig_scope
, orig_import
, &new_scope
, &new_import
);
1237 new_scope
= g_strdup (orig_scope
);
1238 new_import
= g_strdup (orig_import
);
1241 #ifdef ENABLE_NETCORE
1242 // FIXME: these flags are not getting passed correctly
1243 module
= netcore_lookup_native_library (alc
, image
, new_scope
, 0);
1245 module
= legacy_lookup_native_library (image
, new_scope
);
1249 mono_trace (G_LOG_LEVEL_WARNING
, MONO_TRACE_DLLIMPORT
,
1250 "DllImport unable to load library '%s'.",
1253 status_out
->err_code
= LOOKUP_PINVOKE_ERR_NO_LIB
;
1254 status_out
->err_arg
= g_strdup (new_scope
);
1258 mono_trace (G_LOG_LEVEL_INFO
, MONO_TRACE_DLLIMPORT
,
1259 "DllImport searching in: '%s' ('%s').", new_scope
, module
->full_name
);
1261 addr
= pinvoke_probe_for_symbol (module
, piinfo
, new_import
, &error_msg
);
1264 status_out
->err_code
= LOOKUP_PINVOKE_ERR_NO_SYM
;
1265 status_out
->err_arg
= g_strdup (new_import
);
1268 piinfo
->addr
= addr
;
1271 g_free ((char *)new_import
);
1272 g_free ((char *)new_scope
);
1278 pinvoke_probe_for_symbol (MonoDl
*module
, MonoMethodPInvoke
*piinfo
, const char *import
, char **error_msg_out
)
1280 char *error_msg
= NULL
;
1281 gpointer addr
= NULL
;
1283 g_assert (error_msg_out
);
1286 if (import
&& import
[0] == '#' && isdigit (import
[1])) {
1290 id
= strtol (import
+ 1, &end
, 10);
1291 if (id
> 0 && *end
== '\0')
1295 mono_trace (G_LOG_LEVEL_INFO
, MONO_TRACE_DLLIMPORT
,
1296 "Searching for '%s'.", import
);
1298 if (piinfo
->piflags
& PINVOKE_ATTRIBUTE_NO_MANGLE
)
1299 error_msg
= mono_dl_symbol (module
, import
, &addr
);
1302 * Search using a variety of mangled names
1304 for (int mangle_stdcall
= 0; mangle_stdcall
<= 1 && addr
== NULL
; mangle_stdcall
++) {
1305 #if HOST_WIN32 && HOST_X86
1306 const int max_managle_param_count
= (mangle_stdcall
== 0) ? 0 : 256;
1308 const int max_managle_param_count
= 0;
1310 for (int mangle_charset
= 0; mangle_charset
<= 1 && addr
== NULL
; mangle_charset
++) {
1311 for (int mangle_param_count
= 0; mangle_param_count
<= max_managle_param_count
&& addr
== NULL
; mangle_param_count
+= 4) {
1313 char *mangled_name
= (char*)import
;
1314 switch (piinfo
->piflags
& PINVOKE_ATTRIBUTE_CHAR_SET_MASK
) {
1315 case PINVOKE_ATTRIBUTE_CHAR_SET_UNICODE
:
1316 /* Try the mangled name first */
1317 if (mangle_charset
== 0)
1318 mangled_name
= g_strconcat (import
, "W", (const char*)NULL
);
1320 case PINVOKE_ATTRIBUTE_CHAR_SET_AUTO
:
1322 if (mangle_charset
== 0)
1323 mangled_name
= g_strconcat (import
, "W", (const char*)NULL
);
1325 /* Try the mangled name last */
1326 if (mangle_charset
== 1)
1327 mangled_name
= g_strconcat (import
, "A", (const char*)NULL
);
1330 case PINVOKE_ATTRIBUTE_CHAR_SET_ANSI
:
1332 /* Try the mangled name last */
1333 if (mangle_charset
== 1)
1334 mangled_name
= g_strconcat (import
, "A", (const char*)NULL
);
1338 #if HOST_WIN32 && HOST_X86
1339 /* Try the stdcall mangled name */
1341 * gcc under windows creates mangled names without the underscore, but MS.NET
1342 * doesn't support it, so we doesn't support it either.
1344 if (mangle_stdcall
== 1) {
1345 MonoMethod
*method
= &piinfo
->method
;
1347 if (mangle_param_count
== 0)
1348 param_count
= mono_method_signature_internal (method
)->param_count
* sizeof (gpointer
);
1350 /* Try brute force, since it would be very hard to compute the stack usage correctly */
1351 param_count
= mangle_param_count
;
1353 char *mangled_stdcall_name
= g_strdup_printf ("_%s@%d", mangled_name
, param_count
);
1355 if (mangled_name
!= import
)
1356 g_free (mangled_name
);
1358 mangled_name
= mangled_stdcall_name
;
1361 mono_trace (G_LOG_LEVEL_INFO
, MONO_TRACE_DLLIMPORT
,
1362 "Probing '%s'.", mangled_name
);
1364 error_msg
= mono_dl_symbol (module
, mangled_name
, &addr
);
1367 mono_trace (G_LOG_LEVEL_INFO
, MONO_TRACE_DLLIMPORT
,
1368 "Found as '%s'.", mangled_name
);
1370 mono_trace (G_LOG_LEVEL_INFO
, MONO_TRACE_DLLIMPORT
,
1371 "Could not find '%s' due to '%s'.", mangled_name
, error_msg
);
1376 if (mangled_name
!= import
)
1377 g_free (mangled_name
);
1383 *error_msg_out
= error_msg
;
1387 #ifdef ENABLE_NETCORE
1389 ves_icall_System_Runtime_InteropServices_NativeLibrary_FreeLib (gpointer lib
, MonoError
*error
)
1396 // Don't free __Internal
1397 if (internal_module
&& lib
== internal_module
->handle
)
1400 native_library_lock ();
1402 module
= netcore_handle_lookup (lib
);
1406 ref_count
= mono_refcount_dec (module
);
1410 g_hash_table_remove (native_library_module_map
, module
->handle
);
1411 g_hash_table_add (native_library_module_blacklist
, module
);
1412 mono_dl_close (module
);
1415 native_library_unlock ();
1419 ves_icall_System_Runtime_InteropServices_NativeLibrary_GetSymbol (gpointer lib
, MonoStringHandle symbol_name_handle
, MonoBoolean throw_on_error
, MonoError
*error
)
1422 gpointer symbol
= NULL
;
1427 ERROR_LOCAL_BEGIN (local_error
, error
, throw_on_error
)
1429 symbol_name
= mono_string_handle_to_utf8 (symbol_name_handle
, error
);
1430 goto_if_nok (error
, leave_nolock
);
1432 native_library_lock ();
1434 module
= netcore_handle_lookup (lib
);
1436 mono_error_set_generic_error (error
, "System", "DllNotFoundException", "%p: %s", lib
, symbol_name
);
1437 goto_if_nok (error
, leave
);
1439 mono_dl_symbol (module
, symbol_name
, &symbol
);
1441 mono_error_set_generic_error (error
, "System", "EntryPointNotFoundException", "%s: %s", module
->full_name
, symbol_name
);
1442 goto_if_nok (error
, leave
);
1445 native_library_unlock ();
1448 ERROR_LOCAL_END (local_error
);
1453 // LOCKING: expects you to hold native_library_module_lock
1455 check_native_library_cache (MonoDl
*module
)
1457 gpointer handle
= module
->handle
;
1459 MonoDl
*cached_module
= netcore_handle_lookup (handle
);
1460 if (cached_module
) {
1461 g_free (module
->full_name
);
1463 mono_refcount_inc (cached_module
);
1464 return cached_module
;
1466 g_hash_table_insert (native_library_module_map
, handle
, (gpointer
)module
);
1472 ves_icall_System_Runtime_InteropServices_NativeLibrary_LoadByName (MonoStringHandle lib_name_handle
, MonoReflectionAssemblyHandle assembly_handle
, MonoBoolean has_search_flag
, guint32 search_flag
, MonoBoolean throw_on_error
, MonoError
*error
)
1475 gpointer handle
= NULL
;
1476 MonoAssembly
*assembly
= MONO_HANDLE_GETVAL (assembly_handle
, assembly
);
1477 MonoImage
*image
= mono_assembly_get_image_internal (assembly
);
1480 ERROR_LOCAL_BEGIN (local_error
, error
, throw_on_error
)
1482 lib_name
= mono_string_handle_to_utf8 (lib_name_handle
, error
);
1483 goto_if_nok (error
, leave
);
1485 // FIXME: implement search flag defaults properly
1486 module
= netcore_probe_for_module (image
, lib_name
, has_search_flag
? search_flag
: 0x2);
1488 mono_error_set_generic_error (error
, "System", "DllNotFoundException", "%s", lib_name
);
1489 goto_if_nok (error
, leave
);
1491 native_library_lock ();
1492 module
= check_native_library_cache (module
);
1493 native_library_unlock ();
1495 handle
= module
->handle
;
1498 ERROR_LOCAL_END (local_error
);
1504 ves_icall_System_Runtime_InteropServices_NativeLibrary_LoadFromPath (MonoStringHandle lib_path_handle
, MonoBoolean throw_on_error
, MonoError
*error
)
1507 gpointer handle
= NULL
;
1508 char *error_msg
= NULL
;
1511 ERROR_LOCAL_BEGIN (local_error
, error
, throw_on_error
)
1513 lib_path
= mono_string_handle_to_utf8 (lib_path_handle
, error
);
1514 goto_if_nok (error
, leave
);
1516 module
= mono_dl_open (lib_path
, MONO_DL_LAZY
, &error_msg
);
1518 mono_trace (G_LOG_LEVEL_INFO
, MONO_TRACE_DLLIMPORT
, "DllImport error loading library '%s': '%s'.", lib_path
, error_msg
);
1519 mono_error_set_generic_error (error
, "System", "DllNotFoundException", "'%s': '%s'", lib_path
, error_msg
);
1522 goto_if_nok (error
, leave
);
1524 native_library_lock ();
1525 module
= check_native_library_cache (module
);
1526 native_library_unlock ();
1528 handle
= module
->handle
;
1531 ERROR_LOCAL_END (local_error
);
1539 delete_bundled_libraries (void)
1543 for (list
= bundle_library_paths
; list
!= NULL
; list
= list
->next
){
1544 unlink ((const char*)list
->data
);
1546 rmdir (bundled_dylibrary_directory
);
1551 bundle_save_library_initialize (void)
1553 bundle_save_library_initialized
= TRUE
;
1554 char *path
= g_build_filename (g_get_tmp_dir (), "mono-bundle-XXXXXX", (const char*)NULL
);
1555 bundled_dylibrary_directory
= g_mkdtemp (path
);
1557 if (bundled_dylibrary_directory
== NULL
)
1560 atexit (delete_bundled_libraries
);
1565 mono_loader_save_bundled_library (int fd
, uint64_t offset
, uint64_t size
, const char *destfname
)
1568 char *file
, *buffer
, *err
, *internal_path
;
1569 if (!bundle_save_library_initialized
)
1570 bundle_save_library_initialize ();
1572 file
= g_build_filename (bundled_dylibrary_directory
, destfname
, (const char*)NULL
);
1573 buffer
= g_str_from_file_region (fd
, offset
, size
);
1574 g_file_set_contents (file
, buffer
, size
, NULL
);
1576 lib
= mono_dl_open (file
, MONO_DL_LAZY
, &err
);
1578 fprintf (stderr
, "Error loading shared library: %s %s\n", file
, err
);
1581 // Register the name with "." as this is how it will be found when embedded
1582 internal_path
= g_build_filename (".", destfname
, (const char*)NULL
);
1583 mono_loader_register_module (internal_path
, lib
);
1584 g_free (internal_path
);
1585 bundle_library_paths
= g_slist_append (bundle_library_paths
, file
);