Commit 8ab4a003c8

Andrew Kelley <andrew@ziglang.org>
2021-04-30 05:34:33
stage2: properly free Decl name
Two problems solved: * The Decl name may be allocated with gpa or it may be a reference to the ZIR string table. * The main update() function was freeing the ZIR when we still had Decl objects referencing it.
1 parent 474ade8
Changed files (2)
src/Compilation.zig
@@ -1646,10 +1646,15 @@ pub fn update(self: *Compilation) !void {
 
     // If there are any errors, we anticipate the source files being loaded
     // to report error messages. Otherwise we unload all source files to save memory.
+    // The ZIR needs to stay loaded in memory because (1) Decl objects contain references
+    // to it, and (2) generic instantiations, comptime calls, inline calls will need
+    // to reference the ZIR.
     if (self.totalErrorCount() == 0 and !self.keep_source_files_loaded) {
         if (self.bin_file.options.module) |module| {
             for (module.import_table.items()) |entry| {
-                entry.value.unload(self.gpa);
+                const file = entry.value;
+                file.unloadTree(self.gpa);
+                file.unloadSource(self.gpa);
             }
         }
     }
src/Module.zig
@@ -263,9 +263,20 @@ pub const Decl = struct {
         false,
     );
 
+    pub fn clearName(decl: *Decl, gpa: *Allocator) void {
+        // name could be allocated in the ZIR or it could be owned by gpa.
+        const file = decl.namespace.file_scope;
+        const string_table_start = @ptrToInt(file.zir.string_bytes.ptr);
+        const string_table_end = string_table_start + file.zir.string_bytes.len;
+        if (@ptrToInt(decl.name) < string_table_start or @ptrToInt(decl.name) >= string_table_end) {
+            gpa.free(mem.spanZ(decl.name));
+        }
+        decl.name = undefined;
+    }
+
     pub fn destroy(decl: *Decl, module: *Module) void {
         const gpa = module.gpa;
-        gpa.free(mem.spanZ(decl.name));
+        decl.clearName(gpa);
         if (decl.has_tv) {
             if (decl.val.castTag(.function)) |payload| {
                 const func = payload.data;