bool is_known_path(fs::path const& path);
void remove_known_path(fs::path const& path);
+ void redirect_dlopen_name(fs::path const& filename, fs::path const& actual_path);
+ bool is_dlopen_redirect_name(fs::path const& filename);
+
std::unordered_map<std::string, fs::path> redirection_map;
+ std::unordered_map<std::string, fs::path> dlopen_redirection_map;
std::unordered_set<std::string> known_path_set;
void set_elevated_privilege(bool elev) { use_fake_elevation = elev; }
redirect_path(fs::path(SYSCONFDIR) / "vulkan" / category_path_name(category), path);
}
+void PlatformShim::redirect_dlopen_name(fs::path const& filename, fs::path const& actual_path) {
+ dlopen_redirection_map[filename.str()] = actual_path;
+}
+
+bool PlatformShim::is_dlopen_redirect_name(fs::path const& filename) { return dlopen_redirection_map.count(filename.str()) == 1; }
+
#endif
#define CLOSEDIR_FUNC_NAME closedir
#define ACCESS_FUNC_NAME access
#define FOPEN_FUNC_NAME fopen
+#define DLOPEN_FUNC_NAME dlopen
#define GETEUID_FUNC_NAME geteuid
#define GETEGID_FUNC_NAME getegid
#if defined(HAVE_SECURE_GETENV)
#define CLOSEDIR_FUNC_NAME my_closedir
#define ACCESS_FUNC_NAME my_access
#define FOPEN_FUNC_NAME my_fopen
+#define DLOPEN_FUNC_NAME my_dlopen
#define GETEUID_FUNC_NAME my_geteuid
#define GETEGID_FUNC_NAME my_getegid
#if defined(HAVE_SECURE_GETENV)
using PFN_CLOSEDIR = int (*)(DIR* dir_stream);
using PFN_ACCESS = int (*)(const char* pathname, int mode);
using PFN_FOPEN = FILE* (*)(const char* filename, const char* mode);
+using PFN_DLOPEN = void* (*)(const char* in_filename, int flags);
using PFN_GETEUID = uid_t (*)(void);
using PFN_GETEGID = gid_t (*)(void);
#if defined(HAVE_SECURE_GETENV) || defined(HAVE___SECURE_GETENV)
#define real_closedir closedir
#define real_access access
#define real_fopen fopen
+#define real_dlopen dlopen
#define real_geteuid geteuid
#define real_getegid getegid
#if defined(HAVE_SECURE_GETENV)
PFN_CLOSEDIR real_closedir = nullptr;
PFN_ACCESS real_access = nullptr;
PFN_FOPEN real_fopen = nullptr;
+PFN_DLOPEN real_dlopen = nullptr;
PFN_GETEUID real_geteuid = nullptr;
PFN_GETEGID real_getegid = nullptr;
#if defined(HAVE_SECURE_GETENV)
return f_ptr;
}
+FRAMEWORK_EXPORT void* DLOPEN_FUNC_NAME(const char* in_filename, int flags) {
+#if !defined(__APPLE__)
+ if (!real_dlopen) real_dlopen = (PFN_DLOPEN)dlsym(RTLD_NEXT, "dlopen");
+#endif
+
+ if (platform_shim.is_dlopen_redirect_name(in_filename)) {
+ return real_dlopen(platform_shim.dlopen_redirection_map[in_filename].c_str(), flags);
+ }
+ return real_dlopen(in_filename, flags);
+}
+
FRAMEWORK_EXPORT uid_t GETEUID_FUNC_NAME(void) {
#if !defined(__APPLE__)
if (!real_geteuid) real_geteuid = (PFN_GETEUID)dlsym(RTLD_NEXT, "geteuid");
__attribute__((used)) static Interposer _interpose_closedir MACOS_ATTRIB = {VOIDP_CAST(my_closedir), VOIDP_CAST(closedir)};
__attribute__((used)) static Interposer _interpose_access MACOS_ATTRIB = {VOIDP_CAST(my_access), VOIDP_CAST(access)};
__attribute__((used)) static Interposer _interpose_fopen MACOS_ATTRIB = {VOIDP_CAST(my_fopen), VOIDP_CAST(fopen)};
+__attribute__((used)) static Interposer _interpose_dlopen MACOS_ATTRIB = {VOIDP_CAST(my_dlopen), VOIDP_CAST(dlopen)};
__attribute__((used)) static Interposer _interpose_euid MACOS_ATTRIB = {VOIDP_CAST(my_geteuid), VOIDP_CAST(geteuid)};
__attribute__((used)) static Interposer _interpose_egid MACOS_ATTRIB = {VOIDP_CAST(my_getegid), VOIDP_CAST(getegid)};
#if defined(HAVE_SECURE_GETENV)
auto new_driver_location = folder->copy_file(icd_details.icd_manifest.lib_path, new_driver_name.str());
+#if COMMON_UNIX_PLATFORMS
+ if (icd_details.use_dynamic_library_default_search_paths) {
+ platform_shim->redirect_dlopen_name(new_driver_name, new_driver_location);
+ }
+#endif
+#if defined(WIN32)
+ if (icd_details.use_dynamic_library_default_search_paths) {
+ SetDefaultDllDirectories(LOAD_LIBRARY_SEARCH_USER_DIRS);
+ AddDllDirectory(conver_str_to_wstr(new_driver_location.parent_path().str()).c_str());
+ }
+#endif
icds.push_back(TestICDHandle(new_driver_location));
icds.back().reset_icd();
- icd_details.icd_manifest.lib_path = new_driver_location.str();
+ icd_details.icd_manifest.lib_path =
+ icd_details.use_dynamic_library_default_search_paths ? new_driver_name.str() : new_driver_location.str();
}
if (icd_details.discovery_type != ManifestDiscoveryType::none) {
std::string full_json_name = icd_details.json_name;
auto new_layer_location = folder.copy_file(layer.lib_path, layer_binary_name.str());
+#if COMMON_UNIX_PLATFORMS
+ if (layer_details.use_dynamic_library_default_search_paths) {
+ platform_shim->redirect_dlopen_name(layer_binary_name, new_layer_location);
+ }
+#endif
+#if defined(WIN32)
+ if (layer_details.use_dynamic_library_default_search_paths) {
+ SetDefaultDllDirectories(LOAD_LIBRARY_SEARCH_USER_DIRS);
+ AddDllDirectory(conver_str_to_wstr(new_layer_location.parent_path().str()).c_str());
+ }
+#endif
+
// Don't load the layer binary if using any of the wrap objects layers, since it doesn't export the same interface
// functions
if (!layer_details.is_fake &&
layers.push_back(TestLayerHandle(new_layer_location));
layers.back().reset_layer();
}
- layer.lib_path = new_layer_location;
+ layer.lib_path = layer_details.use_dynamic_library_default_search_paths ? layer_binary_name : new_layer_location;
}
}
if (layer_details.discovery_type != ManifestDiscoveryType::none) {
struct TestICDDetails {
TestICDDetails(ManifestICD icd_manifest) noexcept : icd_manifest(icd_manifest) {}
- TestICDDetails(fs::path icd_path, uint32_t api_version = VK_API_VERSION_1_0) noexcept {
- icd_manifest.set_lib_path(icd_path.str()).set_api_version(api_version);
+ TestICDDetails(fs::path icd_binary_path, uint32_t api_version = VK_API_VERSION_1_0) noexcept {
+ icd_manifest.set_lib_path(icd_binary_path.str()).set_api_version(api_version);
}
BUILDER_VALUE(TestICDDetails, ManifestICD, icd_manifest, {});
BUILDER_VALUE(TestICDDetails, std::string, json_name, "test_icd");
BUILDER_VALUE(TestICDDetails, bool, disable_icd_inc, false);
BUILDER_VALUE(TestICDDetails, ManifestDiscoveryType, discovery_type, ManifestDiscoveryType::generic);
BUILDER_VALUE(TestICDDetails, bool, is_fake, false);
+ // Dont add any path information to the library_path - force the use of the default search paths
+ BUILDER_VALUE(TestICDDetails, bool, use_dynamic_library_default_search_paths, false);
};
struct TestLayerDetails {
BUILDER_VALUE(TestLayerDetails, std::string, json_name, "test_layer");
BUILDER_VALUE(TestLayerDetails, ManifestDiscoveryType, discovery_type, ManifestDiscoveryType::generic);
BUILDER_VALUE(TestLayerDetails, bool, is_fake, false);
+ // If discovery type is env-var, is_dir controls whether the env-var has the full name to the manifest or just the folder
BUILDER_VALUE(TestLayerDetails, bool, is_dir, true);
+ // Dont add any path information to the library_path - force the use of the default search paths
+ BUILDER_VALUE(TestLayerDetails, bool, use_dynamic_library_default_search_paths, false);
};
// Locations manifests can go in the test framework
std::string make_native(std::string const&);
struct path {
- private:
#if defined(WIN32)
static const char path_separator = '\\';
#elif COMMON_UNIX_PLATFORMS
buffer[ret] = '\0';
return buffer;
}
+
+inline std::wstring conver_str_to_wstr(std::string const& input) {
+ std::wstring output{};
+ output.resize(input.size());
+ size_t characters_converted = 0;
+ mbstowcs_s(&characters_converted, &output[0], output.size() + 1, input.c_str(), input.size());
+ return output;
+}
+
#endif
}
#endif
+TEST(LibraryLoading, SystemLocations) {
+ FrameworkEnvironment env{};
+ EnvVarWrapper ld_library_path("LD_LIBRARY_PATH", env.get_folder(ManifestLocation::driver).location().str());
+ ld_library_path.add_to_list(env.get_folder(ManifestLocation::explicit_layer).location().str());
+
+ env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2).set_use_dynamic_library_default_search_paths(true));
+ env.get_test_icd().physical_devices.push_back({});
+ const char* fake_ext_name = "VK_FAKE_extension";
+ env.get_test_icd().physical_devices.back().add_extension(fake_ext_name);
+
+ const char* layer_name = "TestLayer";
+ env.add_explicit_layer(
+ TestLayerDetails{ManifestLayer{}.add_layer(
+ ManifestLayer::LayerDescription{}.set_name(layer_name).set_lib_path(TEST_LAYER_PATH_EXPORT_VERSION_2)),
+ "test_layer.json"}
+ .set_use_dynamic_library_default_search_paths(true));
+
+ auto props = env.GetLayerProperties(1);
+ ASSERT_TRUE(string_eq(props.at(0).layerName, layer_name));
+
+ InstWrapper inst{env.vulkan_functions};
+ inst.create_info.add_layer(layer_name);
+ FillDebugUtilsCreateDetails(inst.create_info, env.debug_log);
+ inst.CheckCreate();
+
+ auto phys_dev = inst.GetPhysDev();
+
+ auto active_props = inst.GetActiveLayers(phys_dev, 1);
+ ASSERT_TRUE(string_eq(active_props.at(0).layerName, layer_name));
+
+ auto device_extensions = inst.EnumerateDeviceExtensions(phys_dev, 1);
+ ASSERT_TRUE(string_eq(device_extensions.at(0).extensionName, fake_ext_name));
+}
+
#if defined(__linux__) || defined(__FreeBSD__) || defined(__OpenBSD__)
// Check that valid symlinks do not cause the loader to crash when directly in an XDG env-var
TEST(ManifestDiscovery, ValidSymlinkInXDGEnvVar) {