xref: /oneTBB/src/tbb/dynamic_link.cpp (revision a080baf9)
151c0b2f7Stbbdev /*
2b15aabb3Stbbdev     Copyright (c) 2005-2021 Intel Corporation
351c0b2f7Stbbdev 
451c0b2f7Stbbdev     Licensed under the Apache License, Version 2.0 (the "License");
551c0b2f7Stbbdev     you may not use this file except in compliance with the License.
651c0b2f7Stbbdev     You may obtain a copy of the License at
751c0b2f7Stbbdev 
851c0b2f7Stbbdev         http://www.apache.org/licenses/LICENSE-2.0
951c0b2f7Stbbdev 
1051c0b2f7Stbbdev     Unless required by applicable law or agreed to in writing, software
1151c0b2f7Stbbdev     distributed under the License is distributed on an "AS IS" BASIS,
1251c0b2f7Stbbdev     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1351c0b2f7Stbbdev     See the License for the specific language governing permissions and
1451c0b2f7Stbbdev     limitations under the License.
1551c0b2f7Stbbdev */
1651c0b2f7Stbbdev 
1751c0b2f7Stbbdev #include "dynamic_link.h"
1851c0b2f7Stbbdev 
1949e08aacStbbdev #include "oneapi/tbb/detail/_template_helpers.h"
2049e08aacStbbdev #include "oneapi/tbb/detail/_utils.h"
2151c0b2f7Stbbdev 
2251c0b2f7Stbbdev /*
2351c0b2f7Stbbdev     This file is used by both TBB and OpenMP RTL. Do not use __TBB_ASSERT() macro
2451c0b2f7Stbbdev     and runtime_warning() function because they are not available in OpenMP. Use
2551c0b2f7Stbbdev     __TBB_ASSERT_EX and DYNAMIC_LINK_WARNING instead.
2651c0b2f7Stbbdev */
2751c0b2f7Stbbdev 
2851c0b2f7Stbbdev #include <cstdarg>          // va_list etc.
2951c0b2f7Stbbdev #if _WIN32
3051c0b2f7Stbbdev     #include <malloc.h>
3151c0b2f7Stbbdev 
3251c0b2f7Stbbdev     // Unify system calls
3351c0b2f7Stbbdev     #define dlopen( name, flags )   LoadLibrary( name )
3451c0b2f7Stbbdev     #define dlsym( handle, name )   GetProcAddress( handle, name )
3551c0b2f7Stbbdev     #define dlclose( handle )       ( ! FreeLibrary( handle ) )
3651c0b2f7Stbbdev     #define dlerror()               GetLastError()
3751c0b2f7Stbbdev #ifndef PATH_MAX
3851c0b2f7Stbbdev     #define PATH_MAX                MAX_PATH
3951c0b2f7Stbbdev #endif
4051c0b2f7Stbbdev #else /* _WIN32 */
4151c0b2f7Stbbdev     #include <dlfcn.h>
4251c0b2f7Stbbdev     #include <unistd.h>
4351c0b2f7Stbbdev 
4451c0b2f7Stbbdev     #include <cstring>
4551c0b2f7Stbbdev     #include <climits>
4651c0b2f7Stbbdev     #include <cstdlib>
4751c0b2f7Stbbdev #endif /* _WIN32 */
4851c0b2f7Stbbdev 
4951c0b2f7Stbbdev #if __TBB_WEAK_SYMBOLS_PRESENT && !__TBB_DYNAMIC_LOAD_ENABLED
5051c0b2f7Stbbdev     //TODO: use function attribute for weak symbols instead of the pragma.
5151c0b2f7Stbbdev     #pragma weak dlopen
5251c0b2f7Stbbdev     #pragma weak dlsym
5351c0b2f7Stbbdev     #pragma weak dlclose
5451c0b2f7Stbbdev #endif /* __TBB_WEAK_SYMBOLS_PRESENT && !__TBB_DYNAMIC_LOAD_ENABLED */
5551c0b2f7Stbbdev 
5651c0b2f7Stbbdev 
5751c0b2f7Stbbdev #define __USE_STATIC_DL_INIT    ( !__ANDROID__ )
5851c0b2f7Stbbdev 
5951c0b2f7Stbbdev 
6051c0b2f7Stbbdev /*
6151c0b2f7Stbbdev dynamic_link is a common interface for searching for required symbols in an
6251c0b2f7Stbbdev executable and dynamic libraries.
6351c0b2f7Stbbdev 
6451c0b2f7Stbbdev dynamic_link provides certain guarantees:
6551c0b2f7Stbbdev   1. Either all or none of the requested symbols are resolved. Moreover, if
6651c0b2f7Stbbdev   symbols are not resolved, the dynamic_link_descriptor table is not modified;
6751c0b2f7Stbbdev   2. All returned symbols have secured lifetime: this means that none of them
6851c0b2f7Stbbdev   can be invalidated until dynamic_unlink is called;
6951c0b2f7Stbbdev   3. Any loaded library is loaded only via the full path. The full path is that
7051c0b2f7Stbbdev   from which the runtime itself was loaded. (This is done to avoid security
7151c0b2f7Stbbdev   issues caused by loading libraries from insecure paths).
7251c0b2f7Stbbdev 
7351c0b2f7Stbbdev dynamic_link searches for the requested symbols in three stages, stopping as
7451c0b2f7Stbbdev soon as all of the symbols have been resolved.
7551c0b2f7Stbbdev 
7651c0b2f7Stbbdev   1. Search the global scope:
7751c0b2f7Stbbdev     a. On Windows: dynamic_link tries to obtain the handle of the requested
7851c0b2f7Stbbdev     library and if it succeeds it resolves the symbols via that handle.
7951c0b2f7Stbbdev     b. On Linux: dynamic_link tries to search for the symbols in the global
8051c0b2f7Stbbdev     scope via the main program handle. If the symbols are present in the global
8151c0b2f7Stbbdev     scope their lifetime is not guaranteed (since dynamic_link does not know
8251c0b2f7Stbbdev     anything about the library from which they are exported). Therefore it
8351c0b2f7Stbbdev     tries to "pin" the symbols by obtaining the library name and reopening it.
8451c0b2f7Stbbdev     dlopen may fail to reopen the library in two cases:
8551c0b2f7Stbbdev        i. The symbols are exported from the executable. Currently dynamic _link
8651c0b2f7Stbbdev       cannot handle this situation, so it will not find these symbols in this
8751c0b2f7Stbbdev       step.
8851c0b2f7Stbbdev       ii. The necessary library has been unloaded and cannot be reloaded. It
8951c0b2f7Stbbdev       seems there is nothing that can be done in this case. No symbols are
9051c0b2f7Stbbdev       returned.
9151c0b2f7Stbbdev 
9251c0b2f7Stbbdev   2. Dynamic load: an attempt is made to load the requested library via the
9351c0b2f7Stbbdev   full path.
9451c0b2f7Stbbdev     The full path used is that from which the runtime itself was loaded. If the
9551c0b2f7Stbbdev     library can be loaded, then an attempt is made to resolve the requested
9651c0b2f7Stbbdev     symbols in the newly loaded library.
9751c0b2f7Stbbdev     If the symbols are not found the library is unloaded.
9851c0b2f7Stbbdev 
9951c0b2f7Stbbdev   3. Weak symbols: if weak symbols are available they are returned.
10051c0b2f7Stbbdev */
10151c0b2f7Stbbdev 
10251c0b2f7Stbbdev namespace tbb {
10351c0b2f7Stbbdev namespace detail {
10451c0b2f7Stbbdev namespace r1 {
10551c0b2f7Stbbdev 
10651c0b2f7Stbbdev #if __TBB_WEAK_SYMBOLS_PRESENT || __TBB_DYNAMIC_LOAD_ENABLED
10751c0b2f7Stbbdev 
10851c0b2f7Stbbdev #if !defined(DYNAMIC_LINK_WARNING) && !__TBB_WIN8UI_SUPPORT && __TBB_DYNAMIC_LOAD_ENABLED
10951c0b2f7Stbbdev     // Report runtime errors and continue.
11051c0b2f7Stbbdev     #define DYNAMIC_LINK_WARNING dynamic_link_warning
11151c0b2f7Stbbdev     static void dynamic_link_warning( dynamic_link_error_t code, ... ) {
11251c0b2f7Stbbdev         suppress_unused_warning(code);
11351c0b2f7Stbbdev     } // library_warning
11451c0b2f7Stbbdev #endif /* !defined(DYNAMIC_LINK_WARNING) && !__TBB_WIN8UI_SUPPORT && __TBB_DYNAMIC_LOAD_ENABLED */
11551c0b2f7Stbbdev 
11651c0b2f7Stbbdev     static bool resolve_symbols( dynamic_link_handle module, const dynamic_link_descriptor descriptors[], std::size_t required )
11751c0b2f7Stbbdev     {
11851c0b2f7Stbbdev         if ( !module )
11951c0b2f7Stbbdev             return false;
12051c0b2f7Stbbdev 
12151c0b2f7Stbbdev         #if !__TBB_DYNAMIC_LOAD_ENABLED /* only __TBB_WEAK_SYMBOLS_PRESENT is defined */
12251c0b2f7Stbbdev             if ( !dlsym ) return false;
12351c0b2f7Stbbdev         #endif /* !__TBB_DYNAMIC_LOAD_ENABLED */
12451c0b2f7Stbbdev 
12551c0b2f7Stbbdev         const std::size_t n_desc=20; // Usually we don't have more than 20 descriptors per library
12651c0b2f7Stbbdev         __TBB_ASSERT_EX( required <= n_desc, "Too many descriptors is required" );
12751c0b2f7Stbbdev         if ( required > n_desc ) return false;
12851c0b2f7Stbbdev         pointer_to_handler h[n_desc];
12951c0b2f7Stbbdev 
13051c0b2f7Stbbdev         for ( std::size_t k = 0; k < required; ++k ) {
13151c0b2f7Stbbdev             dynamic_link_descriptor const & desc = descriptors[k];
13251c0b2f7Stbbdev             pointer_to_handler addr = (pointer_to_handler)dlsym( module, desc.name );
13351c0b2f7Stbbdev             if ( !addr ) {
13451c0b2f7Stbbdev                 return false;
13551c0b2f7Stbbdev             }
13651c0b2f7Stbbdev             h[k] = addr;
13751c0b2f7Stbbdev         }
13851c0b2f7Stbbdev 
13951c0b2f7Stbbdev         // Commit the entry points.
14051c0b2f7Stbbdev         // Cannot use memset here, because the writes must be atomic.
14151c0b2f7Stbbdev         for( std::size_t k = 0; k < required; ++k )
14251c0b2f7Stbbdev             *descriptors[k].handler = h[k];
14351c0b2f7Stbbdev         return true;
14451c0b2f7Stbbdev     }
14551c0b2f7Stbbdev 
14651c0b2f7Stbbdev #if __TBB_WIN8UI_SUPPORT
14751c0b2f7Stbbdev     bool dynamic_link( const char*  library, const dynamic_link_descriptor descriptors[], std::size_t required, dynamic_link_handle*, int flags ) {
14851c0b2f7Stbbdev         dynamic_link_handle tmp_handle = NULL;
14951c0b2f7Stbbdev         TCHAR wlibrary[256];
15051c0b2f7Stbbdev         if ( MultiByteToWideChar(CP_UTF8, 0, library, -1, wlibrary, 255) == 0 ) return false;
15151c0b2f7Stbbdev         if ( flags & DYNAMIC_LINK_LOAD )
15251c0b2f7Stbbdev             tmp_handle = LoadPackagedLibrary( wlibrary, 0 );
15351c0b2f7Stbbdev         if (tmp_handle != NULL){
15451c0b2f7Stbbdev             return resolve_symbols(tmp_handle, descriptors, required);
15551c0b2f7Stbbdev         }else{
15651c0b2f7Stbbdev             return false;
15751c0b2f7Stbbdev         }
15851c0b2f7Stbbdev     }
15951c0b2f7Stbbdev     void dynamic_unlink( dynamic_link_handle ) {}
16051c0b2f7Stbbdev     void dynamic_unlink_all() {}
16151c0b2f7Stbbdev #else
16251c0b2f7Stbbdev #if __TBB_DYNAMIC_LOAD_ENABLED
16351c0b2f7Stbbdev /*
16451c0b2f7Stbbdev     There is a security issue on Windows: LoadLibrary() may load and execute malicious code.
16551c0b2f7Stbbdev     See http://www.microsoft.com/technet/security/advisory/2269637.mspx for details.
16651c0b2f7Stbbdev     To avoid the issue, we have to pass full path (not just library name) to LoadLibrary. This
16751c0b2f7Stbbdev     function constructs full path to the specified library (it is assumed the library located
16851c0b2f7Stbbdev     side-by-side with the tbb.dll.
16951c0b2f7Stbbdev 
17051c0b2f7Stbbdev     The function constructs absolute path for given relative path. Important: Base directory is not
17151c0b2f7Stbbdev     current one, it is the directory tbb.dll loaded from.
17251c0b2f7Stbbdev 
17351c0b2f7Stbbdev     Example:
17451c0b2f7Stbbdev         Let us assume "tbb.dll" is located in "c:\program files\common\intel\" directory, e.g.
17551c0b2f7Stbbdev         absolute path of the library is "c:\program files\common\intel\tbb.dll". Absolute path for
17651c0b2f7Stbbdev         "tbbmalloc.dll" would be "c:\program files\common\intel\tbbmalloc.dll". Absolute path for
17751c0b2f7Stbbdev         "malloc\tbbmalloc.dll" would be "c:\program files\common\intel\malloc\tbbmalloc.dll".
17851c0b2f7Stbbdev */
17951c0b2f7Stbbdev 
18051c0b2f7Stbbdev     // Struct handle_storage is used by dynamic_link routine to store handles of
18151c0b2f7Stbbdev     // all loaded or pinned dynamic libraries. When TBB is shut down, it calls
18251c0b2f7Stbbdev     // dynamic_unlink_all() that unloads modules referenced by handle_storage.
18351c0b2f7Stbbdev     // This struct should not have any constructors since it may be used before
18451c0b2f7Stbbdev     // the constructor is called.
18551c0b2f7Stbbdev     #define MAX_LOADED_MODULES 8 // The number of maximum possible modules which can be loaded
18651c0b2f7Stbbdev 
18751c0b2f7Stbbdev     using atomic_incrementer = std::atomic<std::size_t>;
18851c0b2f7Stbbdev 
18951c0b2f7Stbbdev     static struct handles_t {
19051c0b2f7Stbbdev         atomic_incrementer my_size;
19151c0b2f7Stbbdev         dynamic_link_handle my_handles[MAX_LOADED_MODULES];
19251c0b2f7Stbbdev 
19351c0b2f7Stbbdev         void add(const dynamic_link_handle &handle) {
19451c0b2f7Stbbdev             const std::size_t ind = my_size++;
19551c0b2f7Stbbdev             __TBB_ASSERT_EX( ind < MAX_LOADED_MODULES, "Too many modules are loaded" );
19651c0b2f7Stbbdev             my_handles[ind] = handle;
19751c0b2f7Stbbdev         }
19851c0b2f7Stbbdev 
19951c0b2f7Stbbdev         void free() {
20051c0b2f7Stbbdev             const std::size_t size = my_size;
20151c0b2f7Stbbdev             for (std::size_t i=0; i<size; ++i)
20251c0b2f7Stbbdev                 dynamic_unlink( my_handles[i] );
20351c0b2f7Stbbdev         }
20451c0b2f7Stbbdev     } handles;
20551c0b2f7Stbbdev 
20651c0b2f7Stbbdev     static std::once_flag init_dl_data_state;
20751c0b2f7Stbbdev 
20851c0b2f7Stbbdev     static struct ap_data_t {
20951c0b2f7Stbbdev         char _path[PATH_MAX+1];
21051c0b2f7Stbbdev         std::size_t _len;
21151c0b2f7Stbbdev     } ap_data;
21251c0b2f7Stbbdev 
21351c0b2f7Stbbdev     static void init_ap_data() {
21451c0b2f7Stbbdev     #if _WIN32
21551c0b2f7Stbbdev         // Get handle of our DLL first.
21651c0b2f7Stbbdev         HMODULE handle;
21751c0b2f7Stbbdev         BOOL brc = GetModuleHandleEx(
21851c0b2f7Stbbdev             GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
21951c0b2f7Stbbdev             (LPCSTR)( & dynamic_link ), // any function inside the library can be used for the address
22051c0b2f7Stbbdev             & handle
22151c0b2f7Stbbdev             );
22251c0b2f7Stbbdev         if ( !brc ) { // Error occurred.
22351c0b2f7Stbbdev             int err = GetLastError();
22451c0b2f7Stbbdev             DYNAMIC_LINK_WARNING( dl_sys_fail, "GetModuleHandleEx", err );
22551c0b2f7Stbbdev             return;
22651c0b2f7Stbbdev         }
22751c0b2f7Stbbdev         // Now get path to our DLL.
22851c0b2f7Stbbdev         DWORD drc = GetModuleFileName( handle, ap_data._path, static_cast< DWORD >( PATH_MAX ) );
22951c0b2f7Stbbdev         if ( drc == 0 ) { // Error occurred.
23051c0b2f7Stbbdev             int err = GetLastError();
23151c0b2f7Stbbdev             DYNAMIC_LINK_WARNING( dl_sys_fail, "GetModuleFileName", err );
23251c0b2f7Stbbdev             return;
23351c0b2f7Stbbdev         }
23451c0b2f7Stbbdev         if ( drc >= PATH_MAX ) { // Buffer too short.
23551c0b2f7Stbbdev             DYNAMIC_LINK_WARNING( dl_buff_too_small );
23651c0b2f7Stbbdev             return;
23751c0b2f7Stbbdev         }
23851c0b2f7Stbbdev         // Find the position of the last backslash.
23951c0b2f7Stbbdev         char *backslash = std::strrchr( ap_data._path, '\\' );
24051c0b2f7Stbbdev 
24151c0b2f7Stbbdev         if ( !backslash ) {    // Backslash not found.
24251c0b2f7Stbbdev             __TBB_ASSERT_EX( backslash!=NULL, "Unbelievable.");
24351c0b2f7Stbbdev             return;
24451c0b2f7Stbbdev         }
24551c0b2f7Stbbdev         __TBB_ASSERT_EX( backslash >= ap_data._path, "Unbelievable.");
24651c0b2f7Stbbdev         ap_data._len = (std::size_t)(backslash - ap_data._path) + 1;
24751c0b2f7Stbbdev         *(backslash+1) = 0;
24851c0b2f7Stbbdev     #else
24951c0b2f7Stbbdev         // Get the library path
25051c0b2f7Stbbdev         Dl_info dlinfo;
25151c0b2f7Stbbdev         int res = dladdr( (void*)&dynamic_link, &dlinfo ); // any function inside the library can be used for the address
25251c0b2f7Stbbdev         if ( !res ) {
25351c0b2f7Stbbdev             char const * err = dlerror();
25451c0b2f7Stbbdev             DYNAMIC_LINK_WARNING( dl_sys_fail, "dladdr", err );
25551c0b2f7Stbbdev             return;
25651c0b2f7Stbbdev         } else {
25751c0b2f7Stbbdev             __TBB_ASSERT_EX( dlinfo.dli_fname!=NULL, "Unbelievable." );
25851c0b2f7Stbbdev         }
25951c0b2f7Stbbdev 
26051c0b2f7Stbbdev         char const *slash = std::strrchr( dlinfo.dli_fname, '/' );
26151c0b2f7Stbbdev         std::size_t fname_len=0;
26251c0b2f7Stbbdev         if ( slash ) {
26351c0b2f7Stbbdev             __TBB_ASSERT_EX( slash >= dlinfo.dli_fname, "Unbelievable.");
26451c0b2f7Stbbdev             fname_len = (std::size_t)(slash - dlinfo.dli_fname) + 1;
26551c0b2f7Stbbdev         }
26651c0b2f7Stbbdev 
26751c0b2f7Stbbdev         std::size_t rc;
26851c0b2f7Stbbdev         if ( dlinfo.dli_fname[0]=='/' ) {
26951c0b2f7Stbbdev             // The library path is absolute
27051c0b2f7Stbbdev             rc = 0;
27151c0b2f7Stbbdev             ap_data._len = 0;
27251c0b2f7Stbbdev         } else {
27351c0b2f7Stbbdev             // The library path is relative so get the current working directory
27451c0b2f7Stbbdev             if ( !getcwd( ap_data._path, sizeof(ap_data._path)/sizeof(ap_data._path[0]) ) ) {
27551c0b2f7Stbbdev                 DYNAMIC_LINK_WARNING( dl_buff_too_small );
27651c0b2f7Stbbdev                 return;
27751c0b2f7Stbbdev             }
27851c0b2f7Stbbdev             ap_data._len = std::strlen( ap_data._path );
27951c0b2f7Stbbdev             ap_data._path[ap_data._len++]='/';
28051c0b2f7Stbbdev             rc = ap_data._len;
28151c0b2f7Stbbdev         }
28251c0b2f7Stbbdev 
28351c0b2f7Stbbdev         if ( fname_len>0 ) {
28451c0b2f7Stbbdev             if ( ap_data._len>PATH_MAX ) {
28551c0b2f7Stbbdev                 DYNAMIC_LINK_WARNING( dl_buff_too_small );
28651c0b2f7Stbbdev                 ap_data._len=0;
28751c0b2f7Stbbdev                 return;
28851c0b2f7Stbbdev             }
28951c0b2f7Stbbdev             std::strncpy( ap_data._path+rc, dlinfo.dli_fname, fname_len );
29051c0b2f7Stbbdev             ap_data._len += fname_len;
29151c0b2f7Stbbdev             ap_data._path[ap_data._len]=0;
29251c0b2f7Stbbdev         }
29351c0b2f7Stbbdev     #endif /* _WIN32 */
29451c0b2f7Stbbdev     }
29551c0b2f7Stbbdev 
29651c0b2f7Stbbdev     static void init_dl_data() {
29751c0b2f7Stbbdev         init_ap_data();
29851c0b2f7Stbbdev     }
29951c0b2f7Stbbdev 
30051c0b2f7Stbbdev     /*
30151c0b2f7Stbbdev         The function constructs absolute path for given relative path. Important: Base directory is not
30251c0b2f7Stbbdev         current one, it is the directory libtbb.so loaded from.
30351c0b2f7Stbbdev 
30451c0b2f7Stbbdev         Arguments:
30551c0b2f7Stbbdev         in  name -- Name of a file (may be with relative path; it must not be an absolute one).
30651c0b2f7Stbbdev         out path -- Buffer to save result (absolute path) to.
30751c0b2f7Stbbdev         in  len  -- Size of buffer.
30851c0b2f7Stbbdev         ret      -- 0         -- Error occurred.
30951c0b2f7Stbbdev                     > len     -- Buffer too short, required size returned.
31051c0b2f7Stbbdev                     otherwise -- Ok, number of characters (incl. terminating null) written to buffer.
31151c0b2f7Stbbdev     */
31251c0b2f7Stbbdev     static std::size_t abs_path( char const * name, char * path, std::size_t len ) {
31351c0b2f7Stbbdev         if ( ap_data._len == 0 )
31451c0b2f7Stbbdev             return 0;
31551c0b2f7Stbbdev 
31651c0b2f7Stbbdev         std::size_t name_len = std::strlen( name );
31751c0b2f7Stbbdev         std::size_t full_len = name_len+ap_data._len;
31851c0b2f7Stbbdev         if ( full_len < len ) {
31951c0b2f7Stbbdev             __TBB_ASSERT( ap_data._path[ap_data._len] == 0, NULL);
32051c0b2f7Stbbdev             __TBB_ASSERT( std::strlen(ap_data._path) == ap_data._len, NULL);
32151c0b2f7Stbbdev             std::strncpy( path, ap_data._path, ap_data._len + 1 );
32251c0b2f7Stbbdev             __TBB_ASSERT( path[ap_data._len] == 0, NULL );
32351c0b2f7Stbbdev             std::strncat( path, name, len - ap_data._len );
32451c0b2f7Stbbdev             __TBB_ASSERT( std::strlen(path) == full_len, NULL );
32551c0b2f7Stbbdev         }
32651c0b2f7Stbbdev         return full_len+1; // +1 for null character
32751c0b2f7Stbbdev     }
32851c0b2f7Stbbdev #endif  // __TBB_DYNAMIC_LOAD_ENABLED
32951c0b2f7Stbbdev     void init_dynamic_link_data() {
33051c0b2f7Stbbdev     #if __TBB_DYNAMIC_LOAD_ENABLED
33151c0b2f7Stbbdev         std::call_once( init_dl_data_state, init_dl_data );
33251c0b2f7Stbbdev     #endif
33351c0b2f7Stbbdev     }
33451c0b2f7Stbbdev 
33551c0b2f7Stbbdev     #if __USE_STATIC_DL_INIT
33651c0b2f7Stbbdev     // ap_data structure is initialized with current directory on Linux.
33751c0b2f7Stbbdev     // So it should be initialized as soon as possible since the current directory may be changed.
33851c0b2f7Stbbdev     // static_init_ap_data object provides this initialization during library loading.
33951c0b2f7Stbbdev     static struct static_init_dl_data_t {
34051c0b2f7Stbbdev         static_init_dl_data_t() {
34151c0b2f7Stbbdev             init_dynamic_link_data();
34251c0b2f7Stbbdev         }
34351c0b2f7Stbbdev     } static_init_dl_data;
34451c0b2f7Stbbdev     #endif
34551c0b2f7Stbbdev 
34651c0b2f7Stbbdev     #if __TBB_WEAK_SYMBOLS_PRESENT
34751c0b2f7Stbbdev     static bool weak_symbol_link( const dynamic_link_descriptor descriptors[], std::size_t required )
34851c0b2f7Stbbdev     {
34951c0b2f7Stbbdev         // Check if the required entries are present in what was loaded into our process.
35051c0b2f7Stbbdev         for ( std::size_t k = 0; k < required; ++k )
35151c0b2f7Stbbdev             if ( !descriptors[k].ptr )
35251c0b2f7Stbbdev                 return false;
35351c0b2f7Stbbdev         // Commit the entry points.
35451c0b2f7Stbbdev         for ( std::size_t k = 0; k < required; ++k )
35551c0b2f7Stbbdev             *descriptors[k].handler = (pointer_to_handler) descriptors[k].ptr;
35651c0b2f7Stbbdev         return true;
35751c0b2f7Stbbdev     }
35851c0b2f7Stbbdev     #else
35951c0b2f7Stbbdev     static bool weak_symbol_link( const dynamic_link_descriptor[], std::size_t ) {
36051c0b2f7Stbbdev         return false;
36151c0b2f7Stbbdev     }
36251c0b2f7Stbbdev     #endif /* __TBB_WEAK_SYMBOLS_PRESENT */
36351c0b2f7Stbbdev 
36451c0b2f7Stbbdev     void dynamic_unlink( dynamic_link_handle handle ) {
36551c0b2f7Stbbdev     #if !__TBB_DYNAMIC_LOAD_ENABLED /* only __TBB_WEAK_SYMBOLS_PRESENT is defined */
36651c0b2f7Stbbdev         if ( !dlclose ) return;
36751c0b2f7Stbbdev     #endif
36851c0b2f7Stbbdev         if ( handle ) {
36951c0b2f7Stbbdev             dlclose( handle );
37051c0b2f7Stbbdev         }
37151c0b2f7Stbbdev     }
37251c0b2f7Stbbdev 
37351c0b2f7Stbbdev     void dynamic_unlink_all() {
37451c0b2f7Stbbdev     #if __TBB_DYNAMIC_LOAD_ENABLED
37551c0b2f7Stbbdev         handles.free();
37651c0b2f7Stbbdev     #endif
37751c0b2f7Stbbdev     }
37851c0b2f7Stbbdev 
37951c0b2f7Stbbdev     static dynamic_link_handle global_symbols_link( const char* library, const dynamic_link_descriptor descriptors[], std::size_t required ) {
38051c0b2f7Stbbdev         dynamic_link_handle library_handle{};
38151c0b2f7Stbbdev #if _WIN32
382478de5b1Stbbdev         auto res = GetModuleHandleEx(0, library, &library_handle);
38351c0b2f7Stbbdev         __TBB_ASSERT_EX(res && library_handle || !res && !library_handle, nullptr);
38451c0b2f7Stbbdev #else /* _WIN32 */
38551c0b2f7Stbbdev     #if !__TBB_DYNAMIC_LOAD_ENABLED /* only __TBB_WEAK_SYMBOLS_PRESENT is defined */
38651c0b2f7Stbbdev         if ( !dlopen ) return 0;
38751c0b2f7Stbbdev     #endif /* !__TBB_DYNAMIC_LOAD_ENABLED */
38851c0b2f7Stbbdev         // RTLD_GLOBAL - to guarantee that old TBB will find the loaded library
38951c0b2f7Stbbdev         // RTLD_NOLOAD - not to load the library without the full path
39051c0b2f7Stbbdev         library_handle = dlopen(library, RTLD_LAZY | RTLD_GLOBAL | RTLD_NOLOAD);
39151c0b2f7Stbbdev #endif /* _WIN32 */
39251c0b2f7Stbbdev         if (library_handle) {
39351c0b2f7Stbbdev             if (!resolve_symbols(library_handle, descriptors, required)) {
39451c0b2f7Stbbdev                 dynamic_unlink(library_handle);
39551c0b2f7Stbbdev                 library_handle = nullptr;
39651c0b2f7Stbbdev             }
39751c0b2f7Stbbdev         }
39851c0b2f7Stbbdev         return library_handle;
39951c0b2f7Stbbdev     }
40051c0b2f7Stbbdev 
40151c0b2f7Stbbdev     static void save_library_handle( dynamic_link_handle src, dynamic_link_handle *dst ) {
40251c0b2f7Stbbdev         __TBB_ASSERT_EX( src, "The library handle to store must be non-zero" );
40351c0b2f7Stbbdev         if ( dst )
40451c0b2f7Stbbdev             *dst = src;
40551c0b2f7Stbbdev     #if __TBB_DYNAMIC_LOAD_ENABLED
40651c0b2f7Stbbdev         else
40751c0b2f7Stbbdev             handles.add( src );
40851c0b2f7Stbbdev     #endif /* __TBB_DYNAMIC_LOAD_ENABLED */
40951c0b2f7Stbbdev     }
41051c0b2f7Stbbdev 
4110354fc10SIvan Kochin #if !_WIN32
4120354fc10SIvan Kochin     int loading_flags(bool local_binding) {
4130354fc10SIvan Kochin         int flags = RTLD_NOW;
4140354fc10SIvan Kochin         if (local_binding) {
4150354fc10SIvan Kochin             flags = flags | RTLD_LOCAL;
416*a080baf9SAlex #if __linux__ && !__ANDROID__ && !__TBB_USE_SANITIZERS
4170354fc10SIvan Kochin             flags = flags | RTLD_DEEPBIND;
418*a080baf9SAlex #endif
4190354fc10SIvan Kochin         } else {
4200354fc10SIvan Kochin             flags = flags | RTLD_GLOBAL;
4210354fc10SIvan Kochin         }
4220354fc10SIvan Kochin         return flags;
4230354fc10SIvan Kochin     }
424112076d0SIlya Isaev #endif
42551c0b2f7Stbbdev 
4260354fc10SIvan Kochin     dynamic_link_handle dynamic_load( const char* library, const dynamic_link_descriptor descriptors[], std::size_t required, bool local_binding ) {
4270354fc10SIvan Kochin         ::tbb::detail::suppress_unused_warning( library, descriptors, required, local_binding );
4280354fc10SIvan Kochin #if __TBB_DYNAMIC_LOAD_ENABLED
42951c0b2f7Stbbdev         std::size_t const len = PATH_MAX + 1;
43051c0b2f7Stbbdev         char path[ len ];
43151c0b2f7Stbbdev         std::size_t rc = abs_path( library, path, len );
43251c0b2f7Stbbdev         if ( 0 < rc && rc <= len ) {
43351c0b2f7Stbbdev #if _WIN32
43451c0b2f7Stbbdev             // Prevent Windows from displaying silly message boxes if it fails to load library
43551c0b2f7Stbbdev             // (e.g. because of MS runtime problems - one of those crazy manifest related ones)
43651c0b2f7Stbbdev             UINT prev_mode = SetErrorMode (SEM_FAILCRITICALERRORS);
43751c0b2f7Stbbdev #endif /* _WIN32 */
438112076d0SIlya Isaev             // The second argument (loading_flags) is ignored on Windows
4390354fc10SIvan Kochin             dynamic_link_handle library_handle = dlopen( path, loading_flags(local_binding) );
44051c0b2f7Stbbdev #if _WIN32
44151c0b2f7Stbbdev             SetErrorMode (prev_mode);
44251c0b2f7Stbbdev #endif /* _WIN32 */
44351c0b2f7Stbbdev             if( library_handle ) {
44451c0b2f7Stbbdev                 if( !resolve_symbols( library_handle, descriptors, required ) ) {
44551c0b2f7Stbbdev                     // The loaded library does not contain all the expected entry points
44651c0b2f7Stbbdev                     dynamic_unlink( library_handle );
44751c0b2f7Stbbdev                     library_handle = NULL;
44851c0b2f7Stbbdev                 }
44951c0b2f7Stbbdev             } else
45051c0b2f7Stbbdev                 DYNAMIC_LINK_WARNING( dl_lib_not_found, path, dlerror() );
45151c0b2f7Stbbdev             return library_handle;
45251c0b2f7Stbbdev         } else if ( rc>len )
45351c0b2f7Stbbdev                 DYNAMIC_LINK_WARNING( dl_buff_too_small );
45451c0b2f7Stbbdev                 // rc == 0 means failing of init_ap_data so the warning has already been issued.
45551c0b2f7Stbbdev 
45651c0b2f7Stbbdev #endif /* __TBB_DYNAMIC_LOAD_ENABLED */
45751c0b2f7Stbbdev             return 0;
45851c0b2f7Stbbdev     }
45951c0b2f7Stbbdev 
46051c0b2f7Stbbdev     bool dynamic_link( const char* library, const dynamic_link_descriptor descriptors[], std::size_t required, dynamic_link_handle *handle, int flags ) {
46151c0b2f7Stbbdev         init_dynamic_link_data();
46251c0b2f7Stbbdev 
46351c0b2f7Stbbdev         // TODO: May global_symbols_link find weak symbols?
46451c0b2f7Stbbdev         dynamic_link_handle library_handle = ( flags & DYNAMIC_LINK_GLOBAL ) ? global_symbols_link( library, descriptors, required ) : 0;
46551c0b2f7Stbbdev 
4660354fc10SIvan Kochin #if defined(_MSC_VER) && _MSC_VER <= 1900
4670354fc10SIvan Kochin #pragma warning (push)
4680354fc10SIvan Kochin // MSVC 2015 warning: 'int': forcing value to bool 'true' or 'false'
4690354fc10SIvan Kochin #pragma warning (disable: 4800)
4700354fc10SIvan Kochin #endif
47151c0b2f7Stbbdev         if ( !library_handle && ( flags & DYNAMIC_LINK_LOAD ) )
4723e4ab550SIvan Kochin             library_handle = dynamic_load( library, descriptors, required, flags & DYNAMIC_LINK_LOCAL );
47351c0b2f7Stbbdev 
4740354fc10SIvan Kochin #if defined(_MSC_VER) && _MSC_VER <= 1900
4750354fc10SIvan Kochin #pragma warning (pop)
4760354fc10SIvan Kochin #endif
47751c0b2f7Stbbdev         if ( !library_handle && ( flags & DYNAMIC_LINK_WEAK ) )
47851c0b2f7Stbbdev             return weak_symbol_link( descriptors, required );
47951c0b2f7Stbbdev 
48051c0b2f7Stbbdev         if ( library_handle ) {
48151c0b2f7Stbbdev             save_library_handle( library_handle, handle );
48251c0b2f7Stbbdev             return true;
48351c0b2f7Stbbdev         }
48451c0b2f7Stbbdev         return false;
48551c0b2f7Stbbdev     }
48651c0b2f7Stbbdev 
48751c0b2f7Stbbdev #endif /*__TBB_WIN8UI_SUPPORT*/
48851c0b2f7Stbbdev #else /* __TBB_WEAK_SYMBOLS_PRESENT || __TBB_DYNAMIC_LOAD_ENABLED */
48951c0b2f7Stbbdev     bool dynamic_link( const char*, const dynamic_link_descriptor*, std::size_t, dynamic_link_handle *handle, int ) {
49051c0b2f7Stbbdev         if ( handle )
49151c0b2f7Stbbdev             *handle=0;
49251c0b2f7Stbbdev         return false;
49351c0b2f7Stbbdev     }
49451c0b2f7Stbbdev     void dynamic_unlink( dynamic_link_handle ) {}
49551c0b2f7Stbbdev     void dynamic_unlink_all() {}
49651c0b2f7Stbbdev #endif /* __TBB_WEAK_SYMBOLS_PRESENT || __TBB_DYNAMIC_LOAD_ENABLED */
49751c0b2f7Stbbdev 
49851c0b2f7Stbbdev } // namespace r1
49951c0b2f7Stbbdev } // namespace detail
50051c0b2f7Stbbdev } // namespace tbb
501