| @@ -20,11 +20,40 @@ · 19 unmodified lines |
| 20 | 20 | #define COMPAT_W32DLFCN_H |
| 21 | 21 | |
| 22 | 22 | #ifdef _WIN32 |
| 23 | +#include <stdint.h> |
| 24 | + |
| 23 | 25 | #include <windows.h> |
| 26 | + |
| 24 | 27 | #include "config.h" |
| 25 | | −#if (_WIN32_WINNT < 0x0602) || HAVE_WINRT |
| 28 | +#include "libavutil/macros.h" |
| 26 | 29 | #include "libavutil/wchar_filename.h" |
| 27 | | −#endif |
| 30 | + |
| 31 | +static inline wchar_t *get_module_filename(HMODULE module) |
| 32 | +{ |
| 33 | + wchar_t *path = NULL, *new_path; |
| 34 | + DWORD path_size = 0, path_len; |
| 35 | + |
| 36 | + do { |
| 37 | + path_size = path_size ? FFMIN(2 * path_size, INT16_MAX + 1) : MAX_PATH; |
| 38 | + new_path = av_realloc_array(path, path_size, sizeof *path); |
| 39 | + if (!new_path) { |
| 40 | + av_free(path); |
| 41 | + return NULL; |
| 42 | + } |
| 43 | + path = new_path; |
| 44 | + // Returns path_size in case of insufficient buffer. |
| 45 | + // Whether the error is set or not and whether the output |
| 46 | + // is null-terminated or not depends on the version of Windows. |
| 47 | + path_len = GetModuleFileNameW(module, path, path_size); |
| 48 | + } while (path_len && path_size <= INT16_MAX && path_size <= path_len); |
| 49 | + |
| 50 | + if (!path_len) { |
| 51 | + av_free(path); |
| 52 | + return NULL; |
| 53 | + } |
| 54 | + return path; |
| 55 | +} |
| 56 | + |
| 28 | 57 | /** |
| 29 | 58 | * Safe function used to open dynamic libs. This attempts to improve program security |
| 30 | 59 | * by removing the current directory from the dll search path. Only dll's found in the |
| @@ -34,29 +63,53 @@ · 3 unmodified lines |
| 34 | 63 | */ |
| 35 | 64 | static inline HMODULE win32_dlopen(const char *name) |
| 36 | 65 | { |
| 66 | + wchar_t *name_w; |
| 67 | + HMODULE module = NULL; |
| 68 | + if (utf8towchar(name, &name_w)) |
| 69 | + name_w = NULL; |
| 37 | 70 | #if _WIN32_WINNT < 0x0602 |
| 38 | | − // Need to check if KB2533623 is available |
| 71 | + // On Win7 and earlier we check if KB2533623 is available |
| 39 | 72 | if (!GetProcAddress(GetModuleHandleW(L"kernel32.dll"), "SetDefaultDllDirectories")) { |
| 40 | | − HMODULE module = NULL; |
| 41 | | − wchar_t *path = NULL, *name_w = NULL; |
| 42 | | − DWORD pathlen; |
| 43 | | − if (utf8towchar(name, &name_w)) |
| 73 | + wchar_t *path = NULL, *new_path; |
| 74 | + DWORD pathlen, pathsize, namelen; |
| 75 | + if (!name_w) |
| 44 | 76 | goto exit; |
| 45 | | − path = (wchar_t *)av_calloc(MAX_PATH, sizeof(wchar_t)); |
| 77 | + namelen = wcslen(name_w); |
| 46 | 78 | // Try local directory first |
| 47 | | − pathlen = GetModuleFileNameW(NULL, path, MAX_PATH); |
| 48 | | − pathlen = wcsrchr(path, '\\') - path; |
| 49 | | − if (pathlen == 0 || pathlen + wcslen(name_w) + 2 > MAX_PATH) |
| 79 | + path = get_module_filename(NULL); |
| 80 | + if (!path) |
| 81 | + goto exit; |
| 82 | + new_path = wcsrchr(path, '\\'); |
| 83 | + if (!new_path) |
| 50 | 84 | goto exit; |
| 51 | | − path[pathlen] = '\\'; |
| 85 | + pathlen = new_path - path; |
| 86 | + pathsize = pathlen + namelen + 2; |
| 87 | + new_path = av_realloc_array(path, pathsize, sizeof *path); |
| 88 | + if (!new_path) |
| 89 | + goto exit; |
| 90 | + path = new_path; |
| 52 | 91 | wcscpy(path + pathlen + 1, name_w); |
| 53 | 92 | module = LoadLibraryExW(path, NULL, LOAD_WITH_ALTERED_SEARCH_PATH); |
| 54 | 93 | if (module == NULL) { |
| 55 | 94 | // Next try System32 directory |
| 56 | | − pathlen = GetSystemDirectoryW(path, MAX_PATH); |
| 57 | | − if (pathlen == 0 || pathlen + wcslen(name_w) + 2 > MAX_PATH) |
| 95 | + pathlen = GetSystemDirectoryW(path, pathsize); |
| 96 | + if (!pathlen) |
| 58 | 97 | goto exit; |
| 59 | | − path[pathlen] = '\\'; |
| 98 | + // Buffer is not enough in two cases: |
| 99 | + // 1. system directory + \ + module name |
| 100 | + // 2. system directory even without the module name. |
| 101 | + if (pathlen + namelen + 2 > pathsize) { |
| 102 | + pathsize = pathlen + namelen + 2; |
| 103 | + new_path = av_realloc_array(path, pathsize, sizeof *path); |
| 104 | + if (!new_path) |
| 105 | + goto exit; |
| 106 | + path = new_path; |
| 107 | + // Query again to handle the case #2. |
| 108 | + pathlen = GetSystemDirectoryW(path, pathsize); |
| 109 | + if (!pathlen) |
| 110 | + goto exit; |
| 111 | + } |
| 112 | + path[pathlen] = L'\\'; |
| 60 | 113 | wcscpy(path + pathlen + 1, name_w); |
| 61 | 114 | module = LoadLibraryExW(path, NULL, LOAD_WITH_ALTERED_SEARCH_PATH); |
| 62 | 115 | } |
| @@ -73,16 +126,19 @@ exit: · 10 unmodified lines |
| 73 | 126 | # define LOAD_LIBRARY_SEARCH_SYSTEM32 0x00000800 |
| 74 | 127 | #endif |
| 75 | 128 | #if HAVE_WINRT |
| 76 | | − wchar_t *name_w = NULL; |
| 77 | | − int ret; |
| 78 | | − if (utf8towchar(name, &name_w)) |
| 129 | + if (!name_w) |
| 79 | 130 | return NULL; |
| 80 | | − ret = LoadPackagedLibrary(name_w, 0); |
| 81 | | − av_free(name_w); |
| 82 | | − return ret; |
| 131 | + module = LoadPackagedLibrary(name_w, 0); |
| 83 | 132 | #else |
| 84 | | − return LoadLibraryExA(name, NULL, LOAD_LIBRARY_SEARCH_APPLICATION_DIR | LOAD_LIBRARY_SEARCH_SYSTEM32); |
| 133 | +#define LOAD_FLAGS (LOAD_LIBRARY_SEARCH_APPLICATION_DIR | LOAD_LIBRARY_SEARCH_SYSTEM32) |
| 134 | + /* filename may be be in CP_ACP */ |
| 135 | + if (!name_w) |
| 136 | + return LoadLibraryExA(name, NULL, LOAD_FLAGS); |
| 137 | + module = LoadLibraryExW(name_w, NULL, LOAD_FLAGS); |
| 138 | +#undef LOAD_FLAGS |
| 85 | 139 | #endif |
| 140 | + av_free(name_w); |
| 141 | + return module; |
| 86 | 142 | } |
| 87 | 143 | #define dlopen(name, flags) win32_dlopen(name) |
| 88 | 144 | #define dlclose FreeLibrary |