mirror of
https://codeberg.org/ziglang/zig.git
synced 2025-12-06 05:44:20 +00:00
156 lines
5 KiB
C++
Vendored
156 lines
5 KiB
C++
Vendored
//===-- 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
|