diff options
| author | Alex Rønne Petersen <alex@alexrp.com> | 2025-04-12 18:14:17 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-04-12 18:14:17 +0200 |
| commit | 9352f379e8a08bcc5a3bfc851bfb6c6a662000af (patch) | |
| tree | 9fee8a3b98ab806c02aab3a6e9646ccea08f40f1 /lib/libtsan/sanitizer_common/sanitizer_win_interception.cpp | |
| parent | 4e700fdf8ed01e7fc856e631ceffd6006e6f48df (diff) | |
| parent | 1f896c1bf89aa0e3d2a0dce1f4cf6ba6ce5ae9ed (diff) | |
| download | zig-9352f379e8a08bcc5a3bfc851bfb6c6a662000af.tar.gz zig-9352f379e8a08bcc5a3bfc851bfb6c6a662000af.zip | |
Merge pull request #23529 from alexrp/2879-groundwork
Introduce libzigc for libc function implementations in Zig
Diffstat (limited to 'lib/libtsan/sanitizer_common/sanitizer_win_interception.cpp')
| -rw-r--r-- | lib/libtsan/sanitizer_common/sanitizer_win_interception.cpp | 156 |
1 files changed, 156 insertions, 0 deletions
diff --git a/lib/libtsan/sanitizer_common/sanitizer_win_interception.cpp b/lib/libtsan/sanitizer_common/sanitizer_win_interception.cpp new file mode 100644 index 0000000000..c93a411ff2 --- /dev/null +++ b/lib/libtsan/sanitizer_common/sanitizer_win_interception.cpp @@ -0,0 +1,156 @@ +//===-- sanitizer_win_interception.cpp -------------------- --*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Windows-specific export surface to provide interception for parts of the +// runtime that are always statically linked, both for overriding user-defined +// functions as well as registering weak functions that the ASAN runtime should +// use over defaults. +// +//===----------------------------------------------------------------------===// + +#include "sanitizer_platform.h" +#if SANITIZER_WINDOWS +# include <stddef.h> + +# include "interception/interception.h" +# include "sanitizer_addrhashmap.h" +# include "sanitizer_common.h" +# include "sanitizer_internal_defs.h" +# include "sanitizer_placement_new.h" +# include "sanitizer_win_immortalize.h" +# include "sanitizer_win_interception.h" + +using namespace __sanitizer; + +extern "C" void *__ImageBase; + +namespace __sanitizer { + +static uptr GetSanitizerDllExport(const char *export_name) { + const uptr function_address = + __interception::InternalGetProcAddress(&__ImageBase, export_name); + if (function_address == 0) { + Report("ERROR: Failed to find sanitizer DLL export '%s'\n", export_name); + CHECK("Failed to find sanitizer DLL export" && 0); + } + return function_address; +} + +struct WeakCallbackList { + explicit constexpr WeakCallbackList(RegisterWeakFunctionCallback cb) + : callback(cb), next(nullptr) {} + + static void *operator new(size_t size) { return InternalAlloc(size); } + + static void operator delete(void *p) { InternalFree(p); } + + RegisterWeakFunctionCallback callback; + WeakCallbackList *next; +}; +using WeakCallbackMap = AddrHashMap<WeakCallbackList *, 11>; + +static WeakCallbackMap *GetWeakCallbackMap() { + return &immortalize<WeakCallbackMap>(); +} + +void AddRegisterWeakFunctionCallback(uptr export_address, + RegisterWeakFunctionCallback cb) { + WeakCallbackMap::Handle h_find_or_create(GetWeakCallbackMap(), export_address, + false, true); + CHECK(h_find_or_create.exists()); + if (h_find_or_create.created()) { + *h_find_or_create = new WeakCallbackList(cb); + } else { + (*h_find_or_create)->next = new WeakCallbackList(cb); + } +} + +static void RunWeakFunctionCallbacks(uptr export_address) { + WeakCallbackMap::Handle h_find(GetWeakCallbackMap(), export_address, false, + false); + if (!h_find.exists()) { + return; + } + + WeakCallbackList *list = *h_find; + do { + list->callback(); + } while ((list = list->next)); +} + +} // namespace __sanitizer + +extern "C" __declspec(dllexport) bool __cdecl __sanitizer_override_function( + const char *export_name, const uptr user_function, + uptr *const old_user_function) { + CHECK(export_name); + CHECK(user_function); + + const uptr sanitizer_function = GetSanitizerDllExport(export_name); + + const bool function_overridden = __interception::OverrideFunction( + user_function, sanitizer_function, old_user_function); + if (!function_overridden) { + Report( + "ERROR: Failed to override local function at '%p' with sanitizer " + "function '%s'\n", + user_function, export_name); + CHECK("Failed to replace local function with sanitizer version." && 0); + } + + return function_overridden; +} + +extern "C" + __declspec(dllexport) bool __cdecl __sanitizer_override_function_by_addr( + const uptr source_function, const uptr target_function, + uptr *const old_target_function) { + CHECK(source_function); + CHECK(target_function); + + const bool function_overridden = __interception::OverrideFunction( + target_function, source_function, old_target_function); + if (!function_overridden) { + Report( + "ERROR: Failed to override function at '%p' with function at " + "'%p'\n", + target_function, source_function); + CHECK("Failed to apply function override." && 0); + } + + return function_overridden; +} + +extern "C" + __declspec(dllexport) bool __cdecl __sanitizer_register_weak_function( + const char *export_name, const uptr user_function, + uptr *const old_user_function) { + CHECK(export_name); + CHECK(user_function); + + const uptr sanitizer_function = GetSanitizerDllExport(export_name); + + const bool function_overridden = __interception::OverrideFunction( + sanitizer_function, user_function, old_user_function); + if (!function_overridden) { + Report( + "ERROR: Failed to register local function at '%p' to be used in " + "place of sanitizer function '%s'\n.", + user_function, export_name); + CHECK("Failed to register weak function." && 0); + } + + // Note that thread-safety of RunWeakFunctionCallbacks in InitializeFlags + // depends on __sanitizer_register_weak_functions being called during the + // loader lock. + RunWeakFunctionCallbacks(sanitizer_function); + + return function_overridden; +} + +#endif // SANITIZER_WINDOWS |
