File indexing completed on 2024-12-01 05:11:07
0001 /* 0002 SPDX-FileCopyrightText: 2018 Milian Wolff <mail@milianw.de> 0003 0004 SPDX-License-Identifier: LGPL-2.1-or-later 0005 */ 0006 0007 #define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN 0008 #include "3rdparty/doctest.h" 0009 0010 #include "tempfile.h" 0011 #include "tst_config.h" 0012 0013 #include <benchutil.h> 0014 0015 #include <dlfcn.h> 0016 0017 #include <iostream> 0018 0019 static_assert(RTLD_NOW == 0x2, "RTLD_NOW needs to equal 0x2"); 0020 0021 using heaptrack_inject_t = void (*)(const char*); 0022 using heaptrack_stop_t = void (*)(); 0023 0024 namespace { 0025 template <typename T> 0026 T resolveSymbol(void* handle, const char* symbol) 0027 { 0028 return reinterpret_cast<T>(dlsym(handle, symbol)); 0029 } 0030 0031 heaptrack_inject_t resolveHeaptrackInject(void* handle) 0032 { 0033 return resolveSymbol<heaptrack_inject_t>(handle, "heaptrack_inject"); 0034 } 0035 0036 heaptrack_stop_t resolveHeaptrackStop(void* handle) 0037 { 0038 return resolveSymbol<heaptrack_stop_t>(handle, "heaptrack_stop"); 0039 } 0040 0041 template <typename Load, typename Unload> 0042 void runInjectTest(Load load, Unload unload) 0043 { 0044 REQUIRE(!resolveHeaptrackInject(RTLD_DEFAULT)); 0045 REQUIRE(!resolveHeaptrackStop(RTLD_DEFAULT)); 0046 0047 auto* handle = load(); 0048 REQUIRE(handle); 0049 0050 auto* heaptrack_inject = resolveHeaptrackInject(handle); 0051 REQUIRE(heaptrack_inject); 0052 0053 auto* heaptrack_stop = resolveHeaptrackStop(handle); 0054 REQUIRE(heaptrack_stop); 0055 0056 TempFile file; 0057 0058 heaptrack_inject(file.fileName.c_str()); 0059 0060 auto* p = malloc(100); 0061 escape(p); 0062 free(p); 0063 0064 heaptrack_stop(); 0065 0066 unload(handle); 0067 0068 REQUIRE(!resolveHeaptrackInject(RTLD_DEFAULT)); 0069 REQUIRE(!resolveHeaptrackStop(RTLD_DEFAULT)); 0070 0071 const auto contents = file.readContents(); 0072 REQUIRE(!contents.empty()); 0073 REQUIRE(contents.find("\nA\n") != std::string::npos); 0074 REQUIRE(contents.find("\n+") != std::string::npos); 0075 REQUIRE(contents.find("\n-") != std::string::npos); 0076 } 0077 } 0078 0079 TEST_CASE ("inject via dlopen") { 0080 runInjectTest( 0081 []() -> void* { 0082 dlerror(); // clear error 0083 auto* handle = dlopen(HEAPTRACK_LIB_INJECT_SO, RTLD_NOW); 0084 if (!handle) { 0085 std::cerr << "DLOPEN FAILED: " << dlerror() << std::endl; 0086 } 0087 return handle; 0088 }, 0089 [](void* handle) { dlclose(handle); }); 0090 } 0091 0092 #ifdef __USE_GNU 0093 TEST_CASE ("inject via dlmopen") { 0094 runInjectTest( 0095 []() -> void* { 0096 dlerror(); // clear error 0097 auto* handle = dlmopen(LM_ID_BASE, HEAPTRACK_LIB_INJECT_SO, RTLD_NOW); 0098 if (!handle) { 0099 std::cerr << "DLMOPEN FAILED: " << dlerror() << std::endl; 0100 } 0101 return handle; 0102 }, 0103 [](void* handle) { dlclose(handle); }); 0104 } 0105 #endif 0106 0107 extern "C" { 0108 __attribute__((weak)) void* __libc_dlopen_mode(const char* filename, int flag); 0109 __attribute__((weak)) int __libc_dlclose(void* handle); 0110 } 0111 0112 TEST_CASE ("inject via libc") { 0113 if (!__libc_dlopen_mode) { 0114 INFO("__libc_dlopen_mode symbol not available"); 0115 return; 0116 } 0117 0118 runInjectTest([]() { return __libc_dlopen_mode(HEAPTRACK_LIB_INJECT_SO, 0x80000000 | 0x002); }, 0119 [](void* handle) { __libc_dlclose(handle); }); 0120 }