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