Commit 665f13b0cd

mlugg <mlugg@mlugg.co.uk>
2025-09-02 19:47:31
SelfInfo deinit magic
1 parent ba3f389
Changed files (4)
lib/std/debug/SelfInfo/DarwinModule.zig
@@ -578,9 +578,7 @@ fn unwindFrameMachO(
     return new_ip;
 }
 /// No cache needed, because `_dyld_get_image_header` etc are already fast.
-pub const LookupCache = struct {
-    pub const init: LookupCache = .{};
-};
+pub const LookupCache = void;
 pub const DebugInfo = struct {
     unwind: ?struct {
         // Backed by the in-memory sections mapped by the loader
@@ -601,22 +599,24 @@ pub const DebugInfo = struct {
         .full = null,
     };
 
+    pub fn deinit(di: *DebugInfo, gpa: Allocator) void {
+        if (di.full) |*full| {
+            for (full.ofiles.values()) |*ofile| {
+                ofile.dwarf.deinit(gpa);
+                ofile.addr_table.deinit(gpa);
+            }
+            full.ofiles.deinit(gpa);
+            gpa.free(full.symbols);
+            posix.munmap(full.mapped_memory);
+        }
+    }
+
     const OFile = struct {
         dwarf: Dwarf,
         // MLUGG TODO: this could use an adapter to just index straight into the strtab!
         addr_table: std.StringArrayHashMapUnmanaged(u64),
     };
 
-    fn deinit(di: *DebugInfo, gpa: Allocator) void {
-        for (di.full.ofiles.values()) |*ofile| {
-            ofile.dwarf.deinit(gpa);
-            ofile.addr_table.deinit(gpa);
-        }
-        di.full.ofiles.deinit();
-        gpa.free(di.full.symbols);
-        posix.munmap(di.full.mapped_memory);
-    }
-
     fn loadOFile(gpa: Allocator, o_file_path: []const u8) !OFile {
         const mapped_mem = try mapDebugInfoFile(o_file_path);
         errdefer posix.munmap(mapped_mem);
lib/std/debug/SelfInfo/ElfModule.zig
@@ -4,9 +4,7 @@ build_id: ?[]const u8,
 gnu_eh_frame: ?[]const u8,
 
 /// No cache needed, because `dl_iterate_phdr` is already fast.
-pub const LookupCache = struct {
-    pub const init: LookupCache = .{};
-};
+pub const LookupCache = void;
 
 pub const DebugInfo = struct {
     loaded_elf: ?Dwarf.ElfModule,
@@ -15,6 +13,9 @@ pub const DebugInfo = struct {
         .loaded_elf = null,
         .unwind = null,
     };
+    pub fn deinit(di: *DebugInfo, gpa: Allocator) void {
+        if (di.loaded_elf) |*loaded_elf| loaded_elf.deinit(gpa);
+    }
 };
 
 pub fn key(m: ElfModule) usize {
lib/std/debug/SelfInfo/WindowsModule.zig
@@ -167,6 +167,9 @@ fn loadLocationInfo(module: *const WindowsModule, gpa: Allocator, di: *DebugInfo
 pub const LookupCache = struct {
     modules: std.ArrayListUnmanaged(windows.MODULEENTRY32),
     pub const init: LookupCache = .{ .modules = .empty };
+    pub fn deinit(lc: *LookupCache, gpa: Allocator) void {
+        lc.modules.deinit(gpa);
+    }
 };
 pub const DebugInfo = struct {
     loaded: bool,
@@ -176,12 +179,6 @@ pub const DebugInfo = struct {
         file: fs.File,
         section_handle: windows.HANDLE,
         section_view: []const u8,
-        fn deinit(mapped: @This()) void {
-            const process_handle = windows.GetCurrentProcess();
-            assert(windows.ntdll.NtUnmapViewOfSection(process_handle, @constCast(mapped.section_view.ptr)) == .SUCCESS);
-            windows.CloseHandle(mapped.section_handle);
-            mapped.file.close();
-        }
     },
 
     dwarf: ?Dwarf,
@@ -199,11 +196,17 @@ pub const DebugInfo = struct {
         .coff_section_headers = &.{},
     };
 
-    fn deinit(di: *DebugInfo, gpa: Allocator) void {
+    pub fn deinit(di: *DebugInfo, gpa: Allocator) void {
+        if (!di.loaded) return;
         if (di.dwarf) |*dwarf| dwarf.deinit(gpa);
         if (di.pdb) |*pdb| pdb.deinit();
         gpa.free(di.coff_section_headers);
-        if (di.mapped_file) |mapped| mapped.deinit();
+        if (di.mapped_file) |mapped| {
+            const process_handle = windows.GetCurrentProcess();
+            assert(windows.ntdll.NtUnmapViewOfSection(process_handle, @constCast(mapped.section_view.ptr)) == .SUCCESS);
+            windows.CloseHandle(mapped.section_handle);
+            mapped.file.close();
+        }
     }
 
     fn getSymbolFromPdb(di: *DebugInfo, relocated_address: usize) !?std.debug.Symbol {
lib/std/debug/SelfInfo.zig
@@ -18,7 +18,7 @@ const regValueNative = Dwarf.abi.regValueNative;
 
 const SelfInfo = @This();
 
-modules: std.AutoHashMapUnmanaged(usize, Module.DebugInfo),
+modules: std.AutoArrayHashMapUnmanaged(usize, Module.DebugInfo),
 lookup_cache: Module.LookupCache,
 
 /// Indicates whether the `SelfInfo` implementation has support for this target.
@@ -68,18 +68,18 @@ comptime {
 
 pub const init: SelfInfo = .{
     .modules = .empty,
-    .lookup_cache = .init,
+    .lookup_cache = if (Module.LookupCache != void) .init,
 };
 
-pub fn deinit(self: *SelfInfo) void {
-    // MLUGG TODO: that's amusing, this function is straight-up unused. i... wonder if it even should be used anywhere? perhaps not... so perhaps it should not even exist...????
-    var it = self.modules.iterator();
-    while (it.next()) |entry| {
-        const mdi = entry.value_ptr.*;
-        mdi.deinit(self.allocator);
-        self.allocator.destroy(mdi);
-    }
-    self.modules.deinit(self.allocator);
+pub fn deinit(self: *SelfInfo, gpa: Allocator) void {
+    for (self.modules.values()) |*di| di.deinit(gpa);
+    self.modules.deinit(gpa);
+    if (Module.LookupCache != void) self.lookup_cache.deinit(gpa);
+}
+comptime {
+    // `std.debug` does not currently utilize `deinit`, as it keeps hold of debug info for the
+    // whole lifetime of the program. Let's try to avoid it bitrotting.
+    _ = &deinit;
 }
 
 pub fn unwindFrame(self: *SelfInfo, gpa: Allocator, context: *UnwindContext) !usize {
@@ -110,11 +110,12 @@ pub fn getModuleNameForAddress(self: *SelfInfo, gpa: Allocator, address: usize)
 
 /// This type contains the target-specific implementation. It must expose the following declarations:
 ///
-/// * `LookupCache: type`
-///   * `LookupCache.init: LookupCache`
+/// * `LookupCache: type`, with the following declarations unless `LookupCache == void`:
+///   * `init: LookupCache`
+///   * `deinit: fn (*LookupCache, Allocator) void`
 /// * `lookup: fn (*LookupCache, Allocator, address: usize) !Module`
 /// * `key: fn (*const Module) usize`
-/// * `DebugInfo: type`
+/// * `DebugInfo: type`, with the following declarations:
 ///   * `DebugInfo.init: DebugInfo`
 /// * `getSymbolAtAddress: fn (*const Module, Allocator, *DebugInfo, address: usize) !std.debug.Symbol`
 ///