From: Charles Giessen Date: Fri, 4 Mar 2022 17:21:10 +0000 (-0700) Subject: Add live tests for OS dynamic loader behavior X-Git-Tag: upstream/v1.3.207~1 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=6524b598f6c649c4b1881f7cd266d58779169fea;p=platform%2Fupstream%2FVulkan-Loader.git Add live tests for OS dynamic loader behavior Executes various combinations of loading and linking to libraries which export the same symbols. --- diff --git a/tests/live_verification/CMakeLists.txt b/tests/live_verification/CMakeLists.txt index d58f7486..e23643cc 100644 --- a/tests/live_verification/CMakeLists.txt +++ b/tests/live_verification/CMakeLists.txt @@ -16,4 +16,6 @@ # ~~~ add_executable(dynamic_rendering_get_proc_addr dynamic_rendering_get_proc_addr.cpp) -target_link_libraries(dynamic_rendering_get_proc_addr testing_dependencies) \ No newline at end of file +target_link_libraries(dynamic_rendering_get_proc_addr testing_dependencies) + +add_subdirectory(dynamic_loader_behavior) \ No newline at end of file diff --git a/tests/live_verification/dynamic_loader_behavior/CMakeLists.txt b/tests/live_verification/dynamic_loader_behavior/CMakeLists.txt new file mode 100644 index 00000000..29c773a5 --- /dev/null +++ b/tests/live_verification/dynamic_loader_behavior/CMakeLists.txt @@ -0,0 +1,48 @@ +# ~~~ +# Copyright (c) 2022 Valve Corporation +# Copyright (c) 2022 LunarG, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ~~~ + +if (WIN32) + #tests use dlsym and linux specific library names +else() +add_library(dynamic_library_a dynamic_library.cpp) +target_link_libraries(dynamic_library_a PUBLIC testing_framework_util) +target_compile_definitions(dynamic_library_a PRIVATE PRINT_OUTPUT_A) + +add_library(dynamic_library_b dynamic_library.cpp) +target_link_libraries(dynamic_library_b PUBLIC testing_framework_util) +target_compile_definitions(dynamic_library_b PRIVATE PRINT_OUTPUT_B) + +add_library(dynamic_library_c dynamic_library.cpp) +target_link_libraries(dynamic_library_c PUBLIC testing_framework_util) +target_compile_definitions(dynamic_library_c PRIVATE PRINT_OUTPUT_C) + +add_executable(test_dynamic_linking_a_first test_dynamic_linking.cpp) +add_executable(test_dynamic_linking_b_first test_dynamic_linking.cpp) +add_executable(test_dynamic_linking_c_then_load test_dynamic_linking.cpp) +target_link_libraries(test_dynamic_linking_a_first PUBLIC dynamic_library_a dynamic_library_b) +target_link_libraries(test_dynamic_linking_b_first PUBLIC dynamic_library_b dynamic_library_a) +target_link_libraries(test_dynamic_linking_c_then_load PUBLIC dynamic_library_c) +target_compile_definitions(test_dynamic_linking_c_then_load PRIVATE PRINT_OUTPUT_C) + + +add_executable(test_dynamic_loading test_dynamic_loading.cpp) +target_link_libraries(test_dynamic_loading PUBLIC testing_framework_util) + +add_executable(test_dynamic_loading_and_linking test_dynamic_loading_and_linking.cpp) +target_link_libraries(test_dynamic_loading_and_linking PUBLIC testing_framework_util) +target_link_libraries(test_dynamic_loading_and_linking PUBLIC dynamic_library_a) +endif() \ No newline at end of file diff --git a/tests/live_verification/dynamic_loader_behavior/dynamic_library.cpp b/tests/live_verification/dynamic_loader_behavior/dynamic_library.cpp new file mode 100644 index 00000000..3126cad7 --- /dev/null +++ b/tests/live_verification/dynamic_loader_behavior/dynamic_library.cpp @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2022 The Khronos Group Inc. + * Copyright (c) 2022 Valve Corporation + * Copyright (c) 2022 LunarG, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and/or associated documentation files (the "Materials"), to + * deal in the Materials without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Materials, and to permit persons to whom the Materials are + * furnished to do so, subject to the following conditions: + * + * The above copyright notice(s) and this permission notice shall be included in + * all copies or substantial portions of the Materials. + * + * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE MATERIALS OR THE + * USE OR OTHER DEALINGS IN THE MATERIALS. + * + * Author: Charles Giessen + */ + +#include "dynamic_library.h" + +FRAMEWORK_EXPORT char do_logic() { +#if defined(PRINT_OUTPUT_A) + return 'A'; +#elif defined(PRINT_OUTPUT_B) + return 'B'; +#elif defined(PRINT_OUTPUT_C) + return 'C'; +#endif +} + +FRAMEWORK_EXPORT void init() { +#if defined(PRINT_OUTPUT_A) + static LibraryWrapper b{}; + static LibraryWrapper a{}; + a = LibraryWrapper{"./libdynamic_library_a.dylib"}; + b = LibraryWrapper{"./libdynamic_library_b.dylib"}; +#endif +} \ No newline at end of file diff --git a/tests/live_verification/dynamic_loader_behavior/dynamic_library.h b/tests/live_verification/dynamic_loader_behavior/dynamic_library.h new file mode 100644 index 00000000..8b6e29a4 --- /dev/null +++ b/tests/live_verification/dynamic_loader_behavior/dynamic_library.h @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2022 The Khronos Group Inc. + * Copyright (c) 2022 Valve Corporation + * Copyright (c) 2022 LunarG, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and/or associated documentation files (the "Materials"), to + * deal in the Materials without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Materials, and to permit persons to whom the Materials are + * furnished to do so, subject to the following conditions: + * + * The above copyright notice(s) and this permission notice shall be included in + * all copies or substantial portions of the Materials. + * + * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE MATERIALS OR THE + * USE OR OTHER DEALINGS IN THE MATERIALS. + * + * Author: Charles Giessen + */ + +#include "test_util.h" + +extern "C" { + +using DoLogicFunction = char (*)(); +#define DO_LOGIC_FUNCTION_NAME "do_logic" +FRAMEWORK_EXPORT char do_logic(); + +using InitFunction = void (*)(); +#define INIT_FUNCTION_NAME "init" +FRAMEWORK_EXPORT void init(); +}; + +#if defined(WIN32) +#ifndef LIB_EXT +#define LIB_EXT "dll" +#endif +#elif defined(__APPLE__) +#ifndef LIB_EXT +#define LIB_EXT "dylib" +#endif +#else +#ifndef LIB_EXT +#define LIB_EXT "so" +#endif +#endif \ No newline at end of file diff --git a/tests/live_verification/dynamic_loader_behavior/dynamic_loading_behavior.md b/tests/live_verification/dynamic_loader_behavior/dynamic_loading_behavior.md new file mode 100644 index 00000000..3f7f5087 --- /dev/null +++ b/tests/live_verification/dynamic_loader_behavior/dynamic_loading_behavior.md @@ -0,0 +1,31 @@ +# General behavior of dynamic linkers on linux and macOS + +## Linking only + +Symbols are found based on link order. If two libraries export the same symbol, +the first library in the link list is the library which is called. + +## Loading + +Applications cannot load symbols without specifying a library. +Putting RTLD_NEXT in dlsym will not find any symbols even if a loaded library +should contain them. +An app _must_ reference a library that was loaded with `dlopen` to be able to +get at its exported symbols through `dlsym`. +If a loaded library loads subsequent libraries, and they all export the same +symbols, the library which the application explicitly loaded is the one whose +symbols are used. + +## Linking and Loading + +Applications can now use RTLD_NEXT to query symbols. +They will always be the first linked library is that exported the symbol. +In other words, loading a library explicitly doesn't change the behavior. + +Similarly, explicitly loaded libraries behave the same. +Symbols from loaded libraries must be referenced to load the symbol, RTLD_NEXT +doesn't work. +If a loaded library subsequently loads another library which exports the same +symbols, then the library the application explicitly loaded is used. +If one of the subsequently loaded libraries happened to be linked, this doesn't +affect the behavior when querying functions from the application loaded library. \ No newline at end of file diff --git a/tests/live_verification/dynamic_loader_behavior/test_dynamic_linking.cpp b/tests/live_verification/dynamic_loader_behavior/test_dynamic_linking.cpp new file mode 100644 index 00000000..2d2d6b35 --- /dev/null +++ b/tests/live_verification/dynamic_loader_behavior/test_dynamic_linking.cpp @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2022 The Khronos Group Inc. + * Copyright (c) 2022 Valve Corporation + * Copyright (c) 2022 LunarG, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and/or associated documentation files (the "Materials"), to + * deal in the Materials without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Materials, and to permit persons to whom the Materials are + * furnished to do so, subject to the following conditions: + * + * The above copyright notice(s) and this permission notice shall be included in + * all copies or substantial portions of the Materials. + * + * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE MATERIALS OR THE + * USE OR OTHER DEALINGS IN THE MATERIALS. + * + * Author: Charles Giessen + */ + +#include "dynamic_library.h" + +int main() { + std::cout << do_logic() << "\n"; +#if defined(PRINT_OUTPUT_C) + LibraryWrapper dynamic_library_c{std::string("./libdynamic_library_c.") + LIB_EXT}; + InitFunction init = dynamic_library_c.get_symbol(INIT_FUNCTION_NAME); + if (init == nullptr) return 1; + init(); + DoLogicFunction do_logic = dynamic_library_c.get_symbol(DO_LOGIC_FUNCTION_NAME); + if (do_logic == nullptr || do_logic() != 'C') return 2; + + do_logic = reinterpret_cast(dlsym(RTLD_NEXT, DO_LOGIC_FUNCTION_NAME)); + if (do_logic == nullptr || do_logic() != 'A') return 3; + std::cout << "Success\n"; +#endif + return 0; +} \ No newline at end of file diff --git a/tests/live_verification/dynamic_loader_behavior/test_dynamic_loading.cpp b/tests/live_verification/dynamic_loader_behavior/test_dynamic_loading.cpp new file mode 100644 index 00000000..118d0051 --- /dev/null +++ b/tests/live_verification/dynamic_loader_behavior/test_dynamic_loading.cpp @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2022 The Khronos Group Inc. + * Copyright (c) 2022 Valve Corporation + * Copyright (c) 2022 LunarG, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and/or associated documentation files (the "Materials"), to + * deal in the Materials without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Materials, and to permit persons to whom the Materials are + * furnished to do so, subject to the following conditions: + * + * The above copyright notice(s) and this permission notice shall be included in + * all copies or substantial portions of the Materials. + * + * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE MATERIALS OR THE + * USE OR OTHER DEALINGS IN THE MATERIALS. + * + * Author: Charles Giessen + */ + +#include "dynamic_library.h" + +int main() { + { + LibraryWrapper dynamic_library_a{std::string("./libdynamic_library_a.") + LIB_EXT}; + LibraryWrapper dynamic_library_b{std::string("./libdynamic_library_b.") + LIB_EXT}; + + DoLogicFunction do_logic = nullptr; + do_logic = dynamic_library_a.get_symbol(DO_LOGIC_FUNCTION_NAME); + if (do_logic == nullptr || do_logic() != 'A') return 1; + do_logic = dynamic_library_b.get_symbol(DO_LOGIC_FUNCTION_NAME); + if (do_logic == nullptr || do_logic() != 'B') return 2; + } + { + LibraryWrapper dynamic_library_c{std::string("./libdynamic_library_c.") + LIB_EXT}; + InitFunction init = dynamic_library_c.get_symbol(INIT_FUNCTION_NAME); + if (init == nullptr) return 3; + init(); + DoLogicFunction do_logic = dynamic_library_c.get_symbol(DO_LOGIC_FUNCTION_NAME); + if (do_logic == nullptr || do_logic() != 'C') return 4; + // should fail because RTLD_NEXT on linux only is for dynamically *linked* libraries + do_logic = reinterpret_cast(dlsym(RTLD_NEXT, DO_LOGIC_FUNCTION_NAME)); + if (do_logic != nullptr) return 5; + } + std::cout << "Success\n"; + return 0; +} diff --git a/tests/live_verification/dynamic_loader_behavior/test_dynamic_loading_and_linking.cpp b/tests/live_verification/dynamic_loader_behavior/test_dynamic_loading_and_linking.cpp new file mode 100644 index 00000000..97b7bd87 --- /dev/null +++ b/tests/live_verification/dynamic_loader_behavior/test_dynamic_loading_and_linking.cpp @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2022 The Khronos Group Inc. + * Copyright (c) 2022 Valve Corporation + * Copyright (c) 2022 LunarG, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and/or associated documentation files (the "Materials"), to + * deal in the Materials without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Materials, and to permit persons to whom the Materials are + * furnished to do so, subject to the following conditions: + * + * The above copyright notice(s) and this permission notice shall be included in + * all copies or substantial portions of the Materials. + * + * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE MATERIALS OR THE + * USE OR OTHER DEALINGS IN THE MATERIALS. + * + * Author: Charles Giessen + */ + +#include "dynamic_library.h" + +int main() { + DoLogicFunction do_logic = nullptr; + do_logic = reinterpret_cast(dlsym(RTLD_NEXT, DO_LOGIC_FUNCTION_NAME)); + if (do_logic == nullptr || do_logic() != 'A') return 1; + + LibraryWrapper dynamic_library_c{std::string("./libdynamic_library_c.") + LIB_EXT}; + InitFunction init = dynamic_library_c.get_symbol(INIT_FUNCTION_NAME); + if (init == nullptr) return 2; + init(); + + do_logic = dynamic_library_c.get_symbol(DO_LOGIC_FUNCTION_NAME); + if (do_logic == nullptr || do_logic() != 'C') return 3; + + do_logic = reinterpret_cast(dlsym(RTLD_NEXT, DO_LOGIC_FUNCTION_NAME)); + if (do_logic == nullptr || do_logic() != 'A') return 4; + + std::cout << "Success\n"; + return 0; +} \ No newline at end of file