aboutsummaryrefslogtreecommitdiff
path: root/lib/std/debug/SelfInfo/WindowsModule.zig
diff options
context:
space:
mode:
authormlugg <mlugg@mlugg.co.uk>2025-09-19 13:35:12 +0100
committermlugg <mlugg@mlugg.co.uk>2025-09-30 13:44:55 +0100
commit099a95041054e456ebefbd75f6a4f9f6961002be (patch)
tree6293805ebdf2664d5b5906e614297972a7c8da6f /lib/std/debug/SelfInfo/WindowsModule.zig
parent9c1821d3bfadc5eddd4dff271a4920c03ee0ffea (diff)
downloadzig-099a95041054e456ebefbd75f6a4f9f6961002be.tar.gz
zig-099a95041054e456ebefbd75f6a4f9f6961002be.zip
std.debug.SelfInfo: thread safety
This has been a TODO for ages, but in the past it didn't really matter because stack traces are typically printed to stderr for which a mutex is held so in practice there was a mutex guarding usage of `SelfInfo`. However, now that `SelfInfo` is also used for simply capturing traces, thread safety is needed. Instead of just a single mutex, though, there are a couple of different mutexes involved; this helps make critical sections smaller, particularly when unwinding the stack as `unwindFrame` doesn't typically need to hold any lock at all.
Diffstat (limited to 'lib/std/debug/SelfInfo/WindowsModule.zig')
-rw-r--r--lib/std/debug/SelfInfo/WindowsModule.zig23
1 files changed, 19 insertions, 4 deletions
diff --git a/lib/std/debug/SelfInfo/WindowsModule.zig b/lib/std/debug/SelfInfo/WindowsModule.zig
index 1fdf69b2a0..1f4139583e 100644
--- a/lib/std/debug/SelfInfo/WindowsModule.zig
+++ b/lib/std/debug/SelfInfo/WindowsModule.zig
@@ -9,14 +9,14 @@ pub fn lookup(cache: *LookupCache, gpa: Allocator, address: usize) std.debug.Sel
if (lookupInCache(cache, address)) |m| return m;
{
// Check a new module hasn't been loaded
+ cache.rwlock.lock();
+ defer cache.rwlock.unlock();
cache.modules.clearRetainingCapacity();
-
const handle = windows.kernel32.CreateToolhelp32Snapshot(windows.TH32CS_SNAPMODULE | windows.TH32CS_SNAPMODULE32, 0);
if (handle == windows.INVALID_HANDLE_VALUE) {
return windows.unexpectedError(windows.GetLastError());
}
defer windows.CloseHandle(handle);
-
var entry: windows.MODULEENTRY32 = undefined;
entry.dwSize = @sizeOf(windows.MODULEENTRY32);
if (windows.kernel32.Module32First(handle, &entry) != 0) {
@@ -30,12 +30,18 @@ pub fn lookup(cache: *LookupCache, gpa: Allocator, address: usize) std.debug.Sel
return error.MissingDebugInfo;
}
pub fn getSymbolAtAddress(module: *const WindowsModule, gpa: Allocator, di: *DebugInfo, address: usize) std.debug.SelfInfo.Error!std.debug.Symbol {
+ // The `Pdb` API doesn't really allow us *any* thread-safe access, and the `Dwarf` API isn't
+ // great for it either; just lock the whole thing.
+ di.mutex.lock();
+ defer di.mutex.unlock();
+
if (!di.loaded) module.loadDebugInfo(gpa, di) catch |err| switch (err) {
error.OutOfMemory, error.InvalidDebugInfo, error.MissingDebugInfo, error.Unexpected => |e| return e,
error.FileNotFound => return error.MissingDebugInfo,
error.UnknownPDBVersion => return error.UnsupportedDebugInfo,
else => return error.ReadFailed,
};
+
// Translate the runtime address into a virtual address into the module
const vaddr = address - module.base_address;
@@ -50,7 +56,9 @@ pub fn getSymbolAtAddress(module: *const WindowsModule, gpa: Allocator, di: *Deb
return error.MissingDebugInfo;
}
-fn lookupInCache(cache: *const LookupCache, address: usize) ?WindowsModule {
+fn lookupInCache(cache: *LookupCache, address: usize) ?WindowsModule {
+ cache.rwlock.lockShared();
+ defer cache.rwlock.unlockShared();
for (cache.modules.items) |*entry| {
const base_address = @intFromPtr(entry.modBaseAddr);
if (address >= base_address and address < base_address + entry.modBaseSize) {
@@ -182,13 +190,19 @@ fn loadDebugInfo(module: *const WindowsModule, gpa: Allocator, di: *DebugInfo) !
di.loaded = true;
}
pub const LookupCache = struct {
+ rwlock: std.Thread.RwLock,
modules: std.ArrayListUnmanaged(windows.MODULEENTRY32),
- pub const init: LookupCache = .{ .modules = .empty };
+ pub const init: LookupCache = .{
+ .rwlock = .{},
+ .modules = .empty,
+ };
pub fn deinit(lc: *LookupCache, gpa: Allocator) void {
lc.modules.deinit(gpa);
}
};
pub const DebugInfo = struct {
+ mutex: std.Thread.Mutex,
+
loaded: bool,
coff_image_base: u64,
@@ -205,6 +219,7 @@ pub const DebugInfo = struct {
coff_section_headers: []coff.SectionHeader,
pub const init: DebugInfo = .{
+ .mutex = .{},
.loaded = false,
.coff_image_base = undefined,
.mapped_file = null,