loader log error if a requested layer not loaded
authorMark Young <marky@lunarg.com>
Thu, 9 Dec 2021 04:16:08 +0000 (21:16 -0700)
committerMark Young <marky@lunarg.com>
Mon, 31 Jan 2022 21:35:07 +0000 (14:35 -0700)
This should throw an error message if a requested layer didn't load.
This could happen if the JSON file is present, but only a library
exists on the system for the wrong target (like 32 vs 64-bit).

If it did fail because of being the wrong bit-type, we report an info
message only, unless it was directly requested by the application.

Modify the improper bit-depth layer loading test so that it is now 4
tests:
 - Verify bad explicit layer generates VK_ERROR_LAYER_NOT_PRESENT error
 - Verify bad implicit layer generates only an info in the loader output
 - Test case with both a bad implicit and explicit layer with INFO logging
   we should see both messages.
 - Test case with both a bad implicit and explicit layer with ERROR logging
   we should see only the explicit failure message.

Report info failure for ICD wrong bit-type as well.

Finally, fixed a small compilation warning for disabled code.

16 files changed:
loader/loader.c
loader/loader_common.h
loader/log.c
loader/vk_loader_platform.h
tests/framework/data/CMakeLists.txt
tests/framework/data/binaries/dummy_library_elf_32.dll [new file with mode: 0755]
tests/framework/data/binaries/dummy_library_elf_64.dll [new file with mode: 0755]
tests/framework/data/binaries/dummy_library_pe_32.so [new file with mode: 0644]
tests/framework/data/binaries/dummy_library_pe_64.so [new file with mode: 0644]
tests/framework/data/binaries/libdummy_library_elf_32.so
tests/framework/data/binaries/libdummy_library_elf_64.so
tests/framework/framework_config.h.in
tests/framework/test_environment.cpp
tests/framework/test_environment.h
tests/loader_alloc_callback_tests.cpp
tests/loader_regression_tests.cpp

index 304311c..bb33e04 100644 (file)
@@ -119,8 +119,9 @@ int loader_closedir(const struct loader_instance *instance, DIR *dir) {
 #endif  // _WIN32
 }
 
-// log error from to library loading
-void loader_log_load_library_error(const struct loader_instance *inst, const char *filename) {
+// Handle error from to library loading
+void loader_handle_load_library_error(const struct loader_instance *inst, const char *filename,
+                                      enum loader_layer_library_status *lib_status) {
     const char *error_message = loader_platform_open_library_error(filename);
     // If the error is due to incompatible architecture (eg 32 bit vs 64 bit), report it with INFO level
     // Discussed in Github issue 262 & 644
@@ -128,6 +129,11 @@ void loader_log_load_library_error(const struct loader_instance *inst, const cha
     VkFlags err_flag = VULKAN_LOADER_ERROR_BIT;
     if (strstr(error_message, "wrong ELF class:") != NULL || strstr(error_message, " with error 193") != NULL) {
         err_flag = VULKAN_LOADER_INFO_BIT;
+        if (NULL != lib_status) {
+            *lib_status = LOADER_LAYER_LIB_ERROR_WRONG_BIT_TYPE;
+        }
+    } else if (NULL != lib_status) {
+        *lib_status = LOADER_LAYER_LIB_ERROR_FAILED_TO_LOAD;
     }
     loader_log(inst, err_flag, 0, error_message);
 }
@@ -1358,7 +1364,7 @@ static VkResult loader_scanned_icd_init(const struct loader_instance *inst, stru
 }
 
 static VkResult loader_scanned_icd_add(const struct loader_instance *inst, struct loader_icd_tramp_list *icd_tramp_list,
-                                       const char *filename, uint32_t api_version) {
+                                       const char *filename, uint32_t api_version, enum loader_layer_library_status *lib_status) {
     loader_platform_dl_handle handle;
     PFN_vkCreateInstance fp_create_inst;
     PFN_vkEnumerateInstanceExtensionProperties fp_get_inst_ext_props;
@@ -1380,7 +1386,7 @@ static VkResult loader_scanned_icd_add(const struct loader_instance *inst, struc
     handle = loader_platform_open_library(filename);
 #endif
     if (NULL == handle) {
-        loader_log_load_library_error(inst, filename);
+        loader_handle_load_library_error(inst, filename, lib_status);
         res = VK_ERROR_INCOMPATIBLE_DRIVER;
         goto out;
     }
@@ -3505,13 +3511,32 @@ VkResult loader_icd_scan(const struct loader_instance *inst, struct loader_icd_t
                     continue;
                 }
                 VkResult icd_add_res = VK_SUCCESS;
-                icd_add_res = loader_scanned_icd_add(inst, icd_tramp_list, fullpath, vers);
+                enum loader_layer_library_status lib_status;
+                icd_add_res = loader_scanned_icd_add(inst, icd_tramp_list, fullpath, vers, &lib_status);
                 if (VK_ERROR_OUT_OF_HOST_MEMORY == icd_add_res) {
                     res = icd_add_res;
                     goto out;
                 } else if (VK_SUCCESS != icd_add_res) {
-                    loader_log(inst, VULKAN_LOADER_ERROR_BIT | VULKAN_LOADER_DRIVER_BIT, 0,
-                               "loader_icd_scan: Failed to add ICD JSON %s.  Skipping ICD JSON.", fullpath);
+                    switch (lib_status) {
+                        case LOADER_LAYER_LIB_NOT_LOADED:
+                        case LOADER_LAYER_LIB_ERROR_FAILED_TO_LOAD:
+                            loader_log(inst, VULKAN_LOADER_ERROR_BIT | VULKAN_LOADER_DRIVER_BIT, 0,
+                                       "loader_icd_scan: Failed loading library associated with ICD JSON %s.Ignoring this JSON",
+                                       fullpath);
+                            break;
+                        case LOADER_LAYER_LIB_ERROR_WRONG_BIT_TYPE: {
+                            loader_log(inst, VULKAN_LOADER_INFO_BIT | VULKAN_LOADER_DRIVER_BIT, 0,
+                                       "Requested layer %s was wrong bit-type. Ignoring this JSON", fullpath);
+                            break;
+                        }
+                        case LOADER_LAYER_LIB_SUCCESS_LOADED:
+                            // Shouldn't be able to reach this but if it is, best to report a debug
+                            loader_log(inst, VULKAN_LOADER_WARN_BIT | VULKAN_LOADER_DRIVER_BIT, 0,
+                                       "Shouldn't reach this. A valid version of requested ICD %s was loaded but something bad "
+                                       "happened afterwards.",
+                                       fullpath);
+                            break;
+                    }
                     cJSON_Delete(inst, json);
                     json = NULL;
                     continue;
@@ -4420,8 +4445,9 @@ struct loader_instance *loader_get_instance(const VkInstance instance) {
 static loader_platform_dl_handle loader_open_layer_file(const struct loader_instance *inst, const char *chain_type,
                                                         struct loader_layer_properties *prop) {
     if ((prop->lib_handle = loader_platform_open_library(prop->lib_name)) == NULL) {
-        loader_log_load_library_error(inst, prop->lib_name);
+        loader_handle_load_library_error(inst, prop->lib_name, &prop->lib_status);
     } else {
+        prop->lib_status = LOADER_LAYER_LIB_SUCCESS_LOADED;
         loader_log(inst, VULKAN_LOADER_DEBUG_BIT | VULKAN_LOADER_LAYER_BIT, 0, "Loading layer library %s", prop->lib_name);
     }
 
@@ -4478,6 +4504,9 @@ static VkResult loader_add_environment_layers(struct loader_instance *inst, cons
     }
     strcpy(name, layer_env);
 
+    loader_log(inst, VULKAN_LOADER_WARN_BIT | VULKAN_LOADER_LAYER_BIT, 0,
+               "loader_add_environment_layers: Env Var %s defined and adding layers %s", env_name, name);
+
     while (name && *name) {
         next = loader_get_next_path(name);
         res = loader_add_layer_name_to_list(inst, name, type_flags, source_list, target_list, expanded_target_list);
@@ -4889,6 +4918,60 @@ VkResult loader_create_instance_chain(const VkInstanceCreateInfo *pCreateInfo, c
         }
     }
 
+    // Make sure each layer requested by the application was actually loaded
+    for (uint32_t exp = 0; exp < inst->expanded_activated_layer_list.count; ++exp) {
+        struct loader_layer_properties *exp_layer_prop = &inst->expanded_activated_layer_list.list[exp];
+        bool found = false;
+        for (uint32_t act = 0; act < num_activated_layers; ++act) {
+            if (!strcmp(activated_layers[act].name, exp_layer_prop->info.layerName)) {
+                found = true;
+                break;
+            }
+        }
+        // If it wasn't found, we want to at least log an error.  However, if it was enabled by the application directly,
+        // we want to return a bad layer error.
+        if (!found) {
+            bool app_requested = false;
+            for (uint32_t act = 0; act < pCreateInfo->enabledLayerCount; ++act) {
+                if (!strcmp(pCreateInfo->ppEnabledLayerNames[act], exp_layer_prop->info.layerName)) {
+                    app_requested = true;
+                    break;
+                }
+            }
+            VkFlags log_flag = VULKAN_LOADER_LAYER_BIT;
+            char ending = '.';
+            if (app_requested) {
+                log_flag |= VULKAN_LOADER_ERROR_BIT;
+                ending = '!';
+            } else {
+                log_flag |= VULKAN_LOADER_INFO_BIT;
+            }
+            switch (exp_layer_prop->lib_status) {
+                case LOADER_LAYER_LIB_NOT_LOADED:
+                    loader_log(inst, log_flag, 0, "Requested layer %s was not loaded%c", exp_layer_prop->info.layerName, ending);
+                    break;
+                case LOADER_LAYER_LIB_ERROR_WRONG_BIT_TYPE: {
+                    loader_log(inst, log_flag, 0, "Requested layer %s was wrong bit-type%c", exp_layer_prop->info.layerName,
+                               ending);
+                    break;
+                }
+                case LOADER_LAYER_LIB_ERROR_FAILED_TO_LOAD:
+                    loader_log(inst, log_flag, 0, "Requested layer %s failed to load%c", exp_layer_prop->info.layerName, ending);
+                    break;
+                case LOADER_LAYER_LIB_SUCCESS_LOADED:
+                    // Shouldn't be able to reach this but if it is, best to report a debug
+                    loader_log(inst, log_flag, 0,
+                               "Shouldn't reach this. A valid version of requested layer %s was loaded but was not found in the "
+                               "list of activated layers%c",
+                               exp_layer_prop->info.layerName, ending);
+                    break;
+            }
+            if (app_requested) {
+                return VK_ERROR_LAYER_NOT_PRESENT;
+            }
+        }
+    }
+
     VkLoaderFeatureFlags feature_flags = 0;
 #if defined(_WIN32)
     feature_flags = windows_initialize_dxgi();
index 0355424..5f92343 100644 (file)
@@ -111,12 +111,23 @@ typedef struct {
     uint16_t patch;
 } loader_api_version;
 
+// Enumeration used to clearly identify reason for library load failure.
+enum loader_layer_library_status {
+    LOADER_LAYER_LIB_NOT_LOADED = 0,
+
+    LOADER_LAYER_LIB_SUCCESS_LOADED = 1,
+
+    LOADER_LAYER_LIB_ERROR_WRONG_BIT_TYPE = 20,
+    LOADER_LAYER_LIB_ERROR_FAILED_TO_LOAD = 21,
+};
+
 struct loader_layer_properties {
     VkLayerProperties info;
     enum layer_type_flags type_flags;
     uint32_t interface_version;  // PFN_vkNegotiateLoaderLayerInterfaceVersion
     char manifest_file_name[MAX_STRING_SIZE];
     char lib_name[MAX_STRING_SIZE];
+    enum loader_layer_library_status lib_status;
     loader_platform_dl_handle lib_handle;
     struct loader_layer_functions functions;
     struct loader_extension_list instance_extension_list;
index 5dd84c8..2a79884 100644 (file)
@@ -105,8 +105,7 @@ void loader_log(const struct loader_instance *inst, VkFlags msg_type, int32_t ms
         VkDebugUtilsMessengerCallbackDataEXT callback_data;
         VkDebugUtilsObjectNameInfoEXT object_name;
 
-        if ((msg_type & VULKAN_LOADER_INFO_BIT) != 0 || (msg_type & VULKAN_LOADER_LAYER_BIT) != 0 ||
-            (msg_type & VULKAN_LOADER_DRIVER_BIT) != 0) {
+        if ((msg_type & VULKAN_LOADER_INFO_BIT) != 0) {
             severity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT;
         } else if ((msg_type & VULKAN_LOADER_WARN_BIT) != 0) {
             severity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT;
@@ -114,6 +113,9 @@ void loader_log(const struct loader_instance *inst, VkFlags msg_type, int32_t ms
             severity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT;
         } else if ((msg_type & VULKAN_LOADER_DEBUG_BIT) != 0) {
             severity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT;
+        } else if ((msg_type & VULKAN_LOADER_LAYER_BIT) != 0 || (msg_type & VULKAN_LOADER_DRIVER_BIT) != 0) {
+            // Just driver or just layer bit should be treated as an info message in debug utils.
+            severity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT;
         }
 
         if ((msg_type & VULKAN_LOADER_PERF_BIT) != 0) {
index 507a901..4c7f0f2 100644 (file)
@@ -427,8 +427,8 @@ static loader_platform_dl_handle loader_platform_open_library(const char *lib_pa
     return lib_handle;
 }
 static char *loader_platform_open_library_error(const char *libPath) {
-    static char errorMsg[164];
-    (void)snprintf(errorMsg, 163, "Failed to open dynamic library \"%s\" with error %lu", libPath, GetLastError());
+    static char errorMsg[512];
+    (void)snprintf(errorMsg, 511, "Failed to open dynamic library \"%s\" with error %lu", libPath, GetLastError());
     return errorMsg;
 }
 static void loader_platform_close_library(loader_platform_dl_handle library) { FreeLibrary(library); }
index 2a48a61..2308347 100644 (file)
@@ -1,24 +1,47 @@
 
 
-# Uncomment to rebuild the targets
 if(UNIX)
-#     add_library(dummy_library_elf_64 SHARED stub.cpp)
-#     set_target_properties(dummy_library_elf_64 PROPERTIES COMPILE_OPTIONS "-m64" LINK_FLAGS "-m64")
-#     add_custom_command(TARGET dummy_library_elf_64 POST_BUILD
-#         COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_FILE:dummy_library_elf_64> ${CMAKE_CURRENT_SOURCE_DIR}/binaries)
+    ### Copy the 64-bit ELF file into the binaries folder for later use.
+    ### Also, copy the 64-bit ELF-but call it a DLL so that we can use the wrong target (ELF vs. PE) on Windows
+    #
+    ### NOTE: Uncomment the following to rebuild the targets
+    #
+    #add_library(dummy_library_elf_64 SHARED stub.cpp)
+    #set_target_properties(dummy_library_elf_64 PROPERTIES COMPILE_OPTIONS "-m64" LINK_FLAGS "-m64")
+    #add_custom_command(TARGET dummy_library_elf_64 POST_BUILD
+    #    COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_FILE:dummy_library_elf_64> ${CMAKE_CURRENT_SOURCE_DIR}/binaries
+    #    COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_FILE:dummy_library_elf_64> ${CMAKE_CURRENT_SOURCE_DIR}/binaries/dummy_library_elf_64.dll)
 
-#     add_library(dummy_library_elf_32 SHARED stub.cpp)
-#     set_target_properties(dummy_library_elf_32 PROPERTIES COMPILE_OPTIONS "-m32" LINK_FLAGS "-m32")
-#     add_custom_command(TARGET dummy_library_elf_32 POST_BUILD
-#         COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_FILE:dummy_library_elf_32> ${CMAKE_CURRENT_SOURCE_DIR}/binaries)
+    ### Copy the 32-bit ELF file into the binaries folder for later use.
+    ### Also, copy the 32-bit ELF-but call it a DLL so that we can use the wrong target (ELF vs. PE) on Windows
+    #
+    ### NOTE: Uncomment the following to rebuild the targets
+    #
+    #add_library(dummy_library_elf_32 SHARED stub.cpp)
+    #set_target_properties(dummy_library_elf_32 PROPERTIES COMPILE_OPTIONS "-m32" LINK_FLAGS "-m32")
+    #add_custom_command(TARGET dummy_library_elf_32 POST_BUILD
+    #    COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_FILE:dummy_library_elf_32> ${CMAKE_CURRENT_SOURCE_DIR}/binaries
+    #    COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_FILE:dummy_library_elf_32> ${CMAKE_CURRENT_SOURCE_DIR}/binaries/dummy_library_elf_32.dll)
 endif()
 
 if(WIN32)
+    ### Copy the 64-bit PE file into the binaries folder for later use.
+    ### Also, copy the 64-bit PE-but call it a SO so that we can use the wrong target (ELF vs. PE) on Linux
+    #
+    ### NOTE: Uncomment the following to rebuild the targets
+    #
     # add_library(dummy_library_pe_64 SHARED stub.cpp)
     # add_custom_command(TARGET dummy_library_pe_64 POST_BUILD
-    #     COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_FILE:dummy_library_pe_64> ${CMAKE_CURRENT_SOURCE_DIR}/binaries)
+    #     COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_FILE:dummy_library_pe_64> ${CMAKE_CURRENT_SOURCE_DIR}/binaries
+    #     COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_FILE:dummy_library_pe_64> ${CMAKE_CURRENT_SOURCE_DIR}/binaries/dummy_library_pe_64.so)
 
+    ### Copy the 32-bit PE file into the binaries folder for later use.
+    ### Also, copy the 32-bit PE-but call it a SO so that we can use the wrong target (ELF vs. PE) on Linux
+    #
+    ### NOTE: Uncomment the following to rebuild the targets
+    #
     # add_library(dummy_library_pe_32 SHARED stub.cpp)
     # add_custom_command(TARGET dummy_library_pe_32 POST_BUILD
-    #     COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_FILE:dummy_library_pe_32> ${CMAKE_CURRENT_SOURCE_DIR}/binaries)
+    #     COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_FILE:dummy_library_pe_32> ${CMAKE_CURRENT_SOURCE_DIR}/binaries
+    #     COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_FILE:dummy_library_pe_32> ${CMAKE_CURRENT_SOURCE_DIR}/binaries/dummy_library_pe_32.so)
 endif()
diff --git a/tests/framework/data/binaries/dummy_library_elf_32.dll b/tests/framework/data/binaries/dummy_library_elf_32.dll
new file mode 100755 (executable)
index 0000000..7c370ba
Binary files /dev/null and b/tests/framework/data/binaries/dummy_library_elf_32.dll differ
diff --git a/tests/framework/data/binaries/dummy_library_elf_64.dll b/tests/framework/data/binaries/dummy_library_elf_64.dll
new file mode 100755 (executable)
index 0000000..8114f42
Binary files /dev/null and b/tests/framework/data/binaries/dummy_library_elf_64.dll differ
diff --git a/tests/framework/data/binaries/dummy_library_pe_32.so b/tests/framework/data/binaries/dummy_library_pe_32.so
new file mode 100644 (file)
index 0000000..65d031d
Binary files /dev/null and b/tests/framework/data/binaries/dummy_library_pe_32.so differ
diff --git a/tests/framework/data/binaries/dummy_library_pe_64.so b/tests/framework/data/binaries/dummy_library_pe_64.so
new file mode 100644 (file)
index 0000000..dcbe023
Binary files /dev/null and b/tests/framework/data/binaries/dummy_library_pe_64.so differ
index 28c6956..7c370ba 100755 (executable)
Binary files a/tests/framework/data/binaries/libdummy_library_elf_32.so and b/tests/framework/data/binaries/libdummy_library_elf_32.so differ
index 3c260e6..8114f42 100755 (executable)
Binary files a/tests/framework/data/binaries/libdummy_library_elf_64.so and b/tests/framework/data/binaries/libdummy_library_elf_64.so differ
index 694a90f..56b218e 100644 (file)
Binary files a/tests/framework/framework_config.h.in and b/tests/framework/framework_config.h.in differ
index e3818d8..9c91a1b 100644 (file)
@@ -210,6 +210,16 @@ void FrameworkEnvironment::add_implicit_layer(ManifestLayer layer_manifest, cons
 void FrameworkEnvironment::add_explicit_layer(ManifestLayer layer_manifest, const std::string& json_name) noexcept {
     add_layer_impl(TestLayerDetails{layer_manifest, json_name}, explicit_layer_folder, ManifestCategory::explicit_layer);
 }
+void FrameworkEnvironment::add_fake_implicit_layer(ManifestLayer layer_manifest, const std::string& json_name) noexcept {
+    TestLayerDetails fake_details{layer_manifest, json_name};
+    fake_details.is_fake = true;
+    add_layer_impl(fake_details, implicit_layer_folder, ManifestCategory::implicit_layer);
+}
+void FrameworkEnvironment::add_fake_explicit_layer(ManifestLayer layer_manifest, const std::string& json_name) noexcept {
+    TestLayerDetails fake_details{layer_manifest, json_name};
+    fake_details.is_fake = true;
+    add_layer_impl(fake_details, explicit_layer_folder, ManifestCategory::explicit_layer);
+}
 void FrameworkEnvironment::add_implicit_layer(TestLayerDetails layer_details) noexcept {
     add_layer_impl(layer_details, implicit_layer_folder, ManifestCategory::implicit_layer);
 }
@@ -228,7 +238,8 @@ void FrameworkEnvironment::add_layer_impl(TestLayerDetails layer_details, fs::Fo
 
             // 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.lib_path.stem().str().find(fs::path(TEST_LAYER_WRAP_OBJECTS).stem().str()) == std::string::npos) {
+            if (!layer_details.is_fake &&
+                layer.lib_path.stem().str().find(fs::path(TEST_LAYER_WRAP_OBJECTS).stem().str()) == std::string::npos) {
                 layers.push_back(TestLayerHandle(new_layer_location));
                 layers.back().reset_layer();
             }
index 26257ff..3a80af6 100644 (file)
@@ -316,6 +316,8 @@ struct FrameworkEnvironment {
     void add_implicit_layer(TestLayerDetails layer_details) noexcept;
     void add_explicit_layer(ManifestLayer layer_manifest, const std::string& json_name) noexcept;
     void add_explicit_layer(TestLayerDetails layer_details) noexcept;
+    void add_fake_implicit_layer(ManifestLayer layer_manifest, const std::string& json_name) noexcept;
+    void add_fake_explicit_layer(ManifestLayer layer_manifest, const std::string& json_name) noexcept;
 
     TestICD& get_test_icd(int index = 0) noexcept;
     TestICD& reset_icd(int index = 0) noexcept;
index b2d7883..c16bfca 100644 (file)
@@ -539,7 +539,7 @@ TEST_F(Allocation, CreateInstanceDeviceIntentionalAllocFail) {
 TEST(TryLoadWrongBinaries, CreateInstanceIntentionalAllocFail) {
     FrameworkEnvironment env{};
     env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2));
-    env.add_icd(TestICDDetails(CURRENT_PLATFORM_DUMMY_BINARY).set_is_fake(true));
+    env.add_icd(TestICDDetails(CURRENT_PLATFORM_DUMMY_BINARY_WRONG_TYPE).set_is_fake(true));
     size_t fail_index = 0;
     VkResult result = VK_ERROR_OUT_OF_HOST_MEMORY;
     while (result == VK_ERROR_OUT_OF_HOST_MEMORY && fail_index <= 10000) {
index 68aa1b4..f83f60c 100644 (file)
@@ -537,7 +537,7 @@ TEST_F(CreateDevice, LayersNotPresent) {
 TEST(TryLoadWrongBinaries, WrongICD) {
     FrameworkEnvironment env{};
     env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2));
-    env.add_icd(TestICDDetails(CURRENT_PLATFORM_DUMMY_BINARY).set_is_fake(true));
+    env.add_icd(TestICDDetails(CURRENT_PLATFORM_DUMMY_BINARY_WRONG_TYPE).set_is_fake(true));
     env.get_test_icd().physical_devices.emplace_back("physical_device_0");
 
     DebugUtilsLogger log{VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT};
@@ -561,26 +561,247 @@ TEST(TryLoadWrongBinaries, WrongICD) {
     ASSERT_EQ(driver_count, 1);
 }
 
+TEST(TryLoadWrongBinaries, WrongExplicit) {
+    FrameworkEnvironment env{};
+    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2));
+    env.get_test_icd().physical_devices.emplace_back("physical_device_0");
+
+    const char* layer_name = "DummyLayerExplicit";
+    env.add_fake_explicit_layer(
+        ManifestLayer{}.add_layer(
+            ManifestLayer::LayerDescription{}.set_name(layer_name).set_lib_path(CURRENT_PLATFORM_DUMMY_BINARY_WRONG_TYPE)),
+        "dummy_test_layer.json");
+
+    uint32_t layer_count = 0;
+    ASSERT_EQ(env.vulkan_functions.vkEnumerateInstanceLayerProperties(&layer_count, nullptr), VK_SUCCESS);
+    ASSERT_EQ(layer_count, 1);
+
+    std::array<VkLayerProperties, 2> layer_props;
+    ASSERT_EQ(env.vulkan_functions.vkEnumerateInstanceLayerProperties(&layer_count, layer_props.data()), VK_SUCCESS);
+    ASSERT_EQ(layer_count, 1);
+
+    DebugUtilsLogger log{VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT};
+    InstWrapper inst{env.vulkan_functions};
+    inst.create_info.add_layer(layer_name);
+    FillDebugUtilsCreateDetails(inst.create_info, log);
+
+    // Explicit layer not found should generate a VK_ERROR_LAYER_NOT_PRESENT error message.
+    inst.CheckCreate(VK_ERROR_LAYER_NOT_PRESENT);
+
+    // Should get an error message for the explicit layer
+#ifndef __APPLE__
+    ASSERT_TRUE(log.find(std::string("Requested layer ") + std::string(layer_name) + std::string(" was wrong bit-type!")));
+#else   // __APPLE__
+    // Apple only throws a wrong library type of error
+    ASSERT_TRUE(log.find(std::string("Requested layer ") + std::string(layer_name) + std::string(" failed to load!")));
+#endif  // __APPLE__
+}
+
+TEST(TryLoadWrongBinaries, WrongImplicit) {
+    FrameworkEnvironment env{};
+    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2));
+    env.get_test_icd().physical_devices.emplace_back("physical_device_0");
+
+    const char* layer_name = "DummyLayerImplicit0";
+    env.add_fake_implicit_layer(ManifestLayer{}.add_layer(ManifestLayer::LayerDescription{}
+                                                              .set_name(layer_name)
+                                                              .set_lib_path(CURRENT_PLATFORM_DUMMY_BINARY_WRONG_TYPE)
+                                                              .set_disable_environment("DISABLE_ENV")),
+                                "dummy_test_layer.json");
+
+    uint32_t layer_count = 0;
+    ASSERT_EQ(env.vulkan_functions.vkEnumerateInstanceLayerProperties(&layer_count, nullptr), VK_SUCCESS);
+    ASSERT_EQ(layer_count, 1);
+
+    std::array<VkLayerProperties, 1> layer_props;
+    ASSERT_EQ(env.vulkan_functions.vkEnumerateInstanceLayerProperties(&layer_count, layer_props.data()), VK_SUCCESS);
+    ASSERT_EQ(layer_count, 1);
+
+    DebugUtilsLogger log{VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT};
+    InstWrapper inst{env.vulkan_functions};
+    FillDebugUtilsCreateDetails(inst.create_info, log);
+
+    // We don't want to return VK_ERROR_LAYER_NOT_PRESENT for missing implicit layers because it's not the
+    // application asking for them.
+    inst.CheckCreate(VK_SUCCESS);
+
+#ifndef __APPLE__
+    // Should get an info message for the bad implicit layer
+    ASSERT_TRUE(log.find(std::string("Requested layer ") + std::string(layer_name) + std::string(" was wrong bit-type.")));
+#else   // __APPLE__
+    // Apple only throws a wrong library type of error
+    ASSERT_TRUE(log.find(std::string("Requested layer ") + std::string(layer_name) + std::string(" failed to load.")));
+#endif  // __APPLE__
+}
+
 TEST(TryLoadWrongBinaries, WrongExplicitAndImplicit) {
     FrameworkEnvironment env{};
     env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2));
     env.get_test_icd().physical_devices.emplace_back("physical_device_0");
 
     const char* layer_name_0 = "DummyLayerExplicit";
-    auto layer_0 = ManifestLayer{}.add_layer(
-        ManifestLayer::LayerDescription{}.set_name(layer_name_0).set_lib_path(CURRENT_PLATFORM_DUMMY_BINARY));
+    env.add_fake_explicit_layer(
+        ManifestLayer{}.add_layer(
+            ManifestLayer::LayerDescription{}.set_name(layer_name_0).set_lib_path(CURRENT_PLATFORM_DUMMY_BINARY_WRONG_TYPE)),
+        "dummy_test_layer_0.json");
+    const char* layer_name_1 = "DummyLayerImplicit";
+    env.add_fake_implicit_layer(ManifestLayer{}.add_layer(ManifestLayer::LayerDescription{}
+                                                              .set_name(layer_name_1)
+                                                              .set_lib_path(CURRENT_PLATFORM_DUMMY_BINARY_WRONG_TYPE)
+                                                              .set_disable_environment("DISABLE_ENV")),
+                                "dummy_test_layer_1.json");
+
+    uint32_t layer_count = 0;
+    ASSERT_EQ(env.vulkan_functions.vkEnumerateInstanceLayerProperties(&layer_count, nullptr), VK_SUCCESS);
+    ASSERT_EQ(layer_count, 2);
+
+    std::array<VkLayerProperties, 2> layer_props;
+    ASSERT_EQ(env.vulkan_functions.vkEnumerateInstanceLayerProperties(&layer_count, layer_props.data()), VK_SUCCESS);
+    ASSERT_EQ(layer_count, 2);
 
-    auto layer_loc_0 = env.explicit_layer_folder.write_manifest("dummy_test_layer_0.json", layer_0.get_manifest_str());
-    env.platform_shim->add_manifest(ManifestCategory::explicit_layer, layer_loc_0);
+    DebugUtilsLogger log{VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT};
+    InstWrapper inst{env.vulkan_functions};
+    inst.create_info.add_layer(layer_name_0);
+    FillDebugUtilsCreateDetails(inst.create_info, log);
+
+    // Explicit layer not found should generate a VK_ERROR_LAYER_NOT_PRESENT error message.
+    inst.CheckCreate(VK_ERROR_LAYER_NOT_PRESENT);
 
+#ifndef __APPLE__
+    // Should get error messages for both (the explicit is second and we don't want the implicit to return before the explicit
+    // triggers a failure during vkCreateInstance)
+    ASSERT_TRUE(log.find(std::string("Requested layer ") + std::string(layer_name_0) + std::string(" was wrong bit-type!")));
+    ASSERT_TRUE(log.find(std::string("Requested layer ") + std::string(layer_name_1) + std::string(" was wrong bit-type.")));
+#else   // __APPLE__
+    // Apple only throws a wrong library type of error
+    ASSERT_TRUE(log.find(std::string("Requested layer ") + std::string(layer_name_0) + std::string(" failed to load!")));
+    ASSERT_TRUE(log.find(std::string("Requested layer ") + std::string(layer_name_1) + std::string(" failed to load.")));
+#endif  // __APPLE__
+}
+
+TEST(TryLoadWrongBinaries, WrongExplicitAndImplicitErrorOnly) {
+    FrameworkEnvironment env{};
+    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2));
+    env.get_test_icd().physical_devices.emplace_back("physical_device_0");
+
+    const char* layer_name_0 = "DummyLayerExplicit";
+    env.add_fake_explicit_layer(
+        ManifestLayer{}.add_layer(
+            ManifestLayer::LayerDescription{}.set_name(layer_name_0).set_lib_path(CURRENT_PLATFORM_DUMMY_BINARY_WRONG_TYPE)),
+        "dummy_test_layer_0.json");
     const char* layer_name_1 = "DummyLayerImplicit";
-    auto layer_1 = ManifestLayer{}.add_layer(ManifestLayer::LayerDescription{}
-                                                 .set_name(layer_name_1)
-                                                 .set_lib_path(CURRENT_PLATFORM_DUMMY_BINARY)
-                                                 .set_disable_environment("DISABLE_ENV"));
+    env.add_fake_implicit_layer(ManifestLayer{}.add_layer(ManifestLayer::LayerDescription{}
+                                                              .set_name(layer_name_1)
+                                                              .set_lib_path(CURRENT_PLATFORM_DUMMY_BINARY_WRONG_TYPE)
+                                                              .set_disable_environment("DISABLE_ENV")),
+                                "dummy_test_layer_1.json");
 
-    auto layer_loc_1 = env.implicit_layer_folder.write_manifest("dummy_test_layer_1.json", layer_1.get_manifest_str());
-    env.platform_shim->add_manifest(ManifestCategory::implicit_layer, layer_loc_1);
+    uint32_t layer_count = 0;
+    ASSERT_EQ(env.vulkan_functions.vkEnumerateInstanceLayerProperties(&layer_count, nullptr), VK_SUCCESS);
+    ASSERT_EQ(layer_count, 2);
+
+    std::array<VkLayerProperties, 2> layer_props;
+    ASSERT_EQ(env.vulkan_functions.vkEnumerateInstanceLayerProperties(&layer_count, layer_props.data()), VK_SUCCESS);
+    ASSERT_EQ(layer_count, 2);
+
+    DebugUtilsLogger log{VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT};
+    InstWrapper inst{env.vulkan_functions};
+    inst.create_info.add_layer(layer_name_0);
+    FillDebugUtilsCreateDetails(inst.create_info, log);
+
+    // Explicit layer not found should generate a VK_ERROR_LAYER_NOT_PRESENT error message.
+    inst.CheckCreate(VK_ERROR_LAYER_NOT_PRESENT);
+
+#ifndef __APPLE__
+    // Should not get an error messages for either
+    ASSERT_TRUE(log.find(std::string("Requested layer ") + std::string(layer_name_0) + std::string(" was wrong bit-type!")));
+    ASSERT_FALSE(log.find(std::string("Requested layer ") + std::string(layer_name_1) + std::string(" was wrong bit-type.")));
+#else   // __APPLE__
+    // Apple only throws a wrong library type of error
+    ASSERT_TRUE(log.find(std::string("Requested layer ") + std::string(layer_name_0) + std::string(" failed to load!")));
+    ASSERT_FALSE(log.find(std::string("Requested layer ") + std::string(layer_name_1) + std::string(" failed to load.")));
+#endif  // __APPLE__
+}
+
+TEST(TryLoadWrongBinaries, BadExplicit) {
+    FrameworkEnvironment env{};
+    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2));
+    env.get_test_icd().physical_devices.emplace_back("physical_device_0");
+
+    const char* layer_name = "DummyLayerExplicit";
+    env.add_fake_explicit_layer(
+        ManifestLayer{}.add_layer(
+            ManifestLayer::LayerDescription{}.set_name(layer_name).set_lib_path(CURRENT_PLATFORM_DUMMY_BINARY_BAD)),
+        "dummy_test_layer.json");
+
+    uint32_t layer_count = 0;
+    ASSERT_EQ(env.vulkan_functions.vkEnumerateInstanceLayerProperties(&layer_count, nullptr), VK_SUCCESS);
+    ASSERT_EQ(layer_count, 1);
+
+    std::array<VkLayerProperties, 2> layer_props;
+    ASSERT_EQ(env.vulkan_functions.vkEnumerateInstanceLayerProperties(&layer_count, layer_props.data()), VK_SUCCESS);
+    ASSERT_EQ(layer_count, 1);
+
+    DebugUtilsLogger log{VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT};
+    InstWrapper inst{env.vulkan_functions};
+    inst.create_info.add_layer(layer_name);
+    FillDebugUtilsCreateDetails(inst.create_info, log);
+
+    // Explicit layer not found should generate a VK_ERROR_LAYER_NOT_PRESENT error message.
+    inst.CheckCreate(VK_ERROR_LAYER_NOT_PRESENT);
+
+    // Should get an error message for the bad explicit
+    ASSERT_TRUE(log.find(std::string("Requested layer ") + std::string(layer_name) + std::string(" failed to load!")));
+}
+
+TEST(TryLoadWrongBinaries, BadImplicit) {
+    FrameworkEnvironment env{};
+    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2));
+    env.get_test_icd().physical_devices.emplace_back("physical_device_0");
+
+    const char* layer_name = "DummyLayerImplicit0";
+    env.add_fake_implicit_layer(ManifestLayer{}.add_layer(ManifestLayer::LayerDescription{}
+                                                              .set_name(layer_name)
+                                                              .set_lib_path(CURRENT_PLATFORM_DUMMY_BINARY_BAD)
+                                                              .set_disable_environment("DISABLE_ENV")),
+                                "dummy_test_layer.json");
+
+    uint32_t layer_count = 0;
+    ASSERT_EQ(env.vulkan_functions.vkEnumerateInstanceLayerProperties(&layer_count, nullptr), VK_SUCCESS);
+    ASSERT_EQ(layer_count, 1);
+
+    std::array<VkLayerProperties, 1> layer_props;
+    ASSERT_EQ(env.vulkan_functions.vkEnumerateInstanceLayerProperties(&layer_count, layer_props.data()), VK_SUCCESS);
+    ASSERT_EQ(layer_count, 1);
+
+    DebugUtilsLogger log{VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT};
+    InstWrapper inst{env.vulkan_functions};
+    FillDebugUtilsCreateDetails(inst.create_info, log);
+
+    // We don't want to return VK_ERROR_LAYER_NOT_PRESENT for missing implicit layers because it's not the
+    // application asking for them.
+    inst.CheckCreate(VK_SUCCESS);
+
+    // Should get an info message for the bad implicit
+    ASSERT_TRUE(log.find(std::string("Requested layer ") + std::string(layer_name) + std::string(" failed to load.")));
+}
+
+TEST(TryLoadWrongBinaries, BadExplicitAndImplicit) {
+    FrameworkEnvironment env{};
+    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2));
+    env.get_test_icd().physical_devices.emplace_back("physical_device_0");
+
+    const char* layer_name_0 = "DummyLayerExplicit";
+    env.add_fake_explicit_layer(
+        ManifestLayer{}.add_layer(
+            ManifestLayer::LayerDescription{}.set_name(layer_name_0).set_lib_path(CURRENT_PLATFORM_DUMMY_BINARY_BAD)),
+        "dummy_test_layer_0.json");
+    const char* layer_name_1 = "DummyLayerImplicit0";
+    env.add_fake_implicit_layer(ManifestLayer{}.add_layer(ManifestLayer::LayerDescription{}
+                                                              .set_name(layer_name_1)
+                                                              .set_lib_path(CURRENT_PLATFORM_DUMMY_BINARY_BAD)
+                                                              .set_disable_environment("DISABLE_ENV")),
+                                "dummy_test_layer_1.json");
 
     uint32_t layer_count = 0;
     ASSERT_EQ(env.vulkan_functions.vkEnumerateInstanceLayerProperties(&layer_count, nullptr), VK_SUCCESS);
@@ -590,18 +811,17 @@ TEST(TryLoadWrongBinaries, WrongExplicitAndImplicit) {
     ASSERT_EQ(env.vulkan_functions.vkEnumerateInstanceLayerProperties(&layer_count, layer_props.data()), VK_SUCCESS);
     ASSERT_EQ(layer_count, 2);
 
+    DebugUtilsLogger log{VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT};
     InstWrapper inst{env.vulkan_functions};
-    inst.create_info.add_layer(layer_name_0).add_layer(layer_name_1);
-    // "According to all known laws of aviation, there is no way that this should return VK_SUCCESS"
-    // This by accounts *should* return VK_ERROR_LAYER_NOT_PRESENT but due to a confluence of bad choices and backwards
-    // compatibility guarantee, returns VK_SUCCESS.
-    // REASON: To be able to 'load' a library in either 32 or 64 bit apps, the loader will just try to load both and ignore
-    // whichever library didn't match the current architecture. Because of this, the loader actually just flat out ignores
-    // errors and pretends they didn't load at all.
-    // TODO: add 32/64 bit field to layer manifests so that this issue doesn't occur, then implement logic to make the loader
-    // smart enough to tell when a layer that failed to load was due to the old behavior or not. (eg, don't report an error if
-    // a layer with the same name successfully loaded)
-    inst.CheckCreate();
+    inst.create_info.add_layer(layer_name_0);
+    FillDebugUtilsCreateDetails(inst.create_info, log);
+
+    // Explicit layer not found should generate a VK_ERROR_LAYER_NOT_PRESENT error message.
+    inst.CheckCreate(VK_ERROR_LAYER_NOT_PRESENT);
+
+    // Apple only throws a wrong library type of error
+    ASSERT_TRUE(log.find(std::string("Requested layer ") + std::string(layer_name_0) + std::string(" failed to load!")));
+    ASSERT_TRUE(log.find(std::string("Requested layer ") + std::string(layer_name_1) + std::string(" failed to load.")));
 }
 
 TEST_F(EnumeratePhysicalDeviceGroups, OneCall) {