aboutsummaryrefslogtreecommitdiff
path: root/lib/libtsan/sanitizer_common/sanitizer_win_interception.cpp
diff options
context:
space:
mode:
authorAlex Rønne Petersen <alex@alexrp.com>2025-04-12 18:14:17 +0200
committerGitHub <noreply@github.com>2025-04-12 18:14:17 +0200
commit9352f379e8a08bcc5a3bfc851bfb6c6a662000af (patch)
tree9fee8a3b98ab806c02aab3a6e9646ccea08f40f1 /lib/libtsan/sanitizer_common/sanitizer_win_interception.cpp
parent4e700fdf8ed01e7fc856e631ceffd6006e6f48df (diff)
parent1f896c1bf89aa0e3d2a0dce1f4cf6ba6ce5ae9ed (diff)
downloadzig-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.cpp156
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