Skip to content

Commit 44faea9

Browse files
committed
fix: heap-paranoia false-positive from free-before-publish ordering
tplAddFunc (template.zig) and mapSet (vm_map.zig) freed the old managed slice before repointing the object's field to the new one, so heap-paranoia's live-object scan caught the object still referencing the bytes being freed. Publish first, then free, matching the pattern already established in mapInsertHashed/vm.zig/template.zig elsewhere in this file.
1 parent 1eb4e61 commit 44faea9

2 files changed

Lines changed: 7 additions & 2 deletions

File tree

src/lang/native/template.zig

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -791,8 +791,10 @@ pub fn tplAddFunc(ctx: VMContext, tmpl_obj: *Object, name: []const u8, func_val:
791791
const m_now = funcs_obj.map_managed;
792792
@memcpy(new_items[0..old_len], m_now[0..old_len]);
793793
new_items[old_len] = .{ .key = .{ .string = try ctx.cs.internStr(name) }, .value = func_val };
794-
ctx.hs.freeManagedSlice(MapEntry, m_now);
794+
// Publish before freeing the old slice so paranoia doesn't see a
795+
// live object (funcs_obj) still pointing at the bytes being freed.
795796
funcs_obj.* = .{ .map_managed = new_items[0 .. old_len + 1] };
797+
ctx.hs.freeManagedSlice(MapEntry, m_now);
796798
},
797799
else => return error.TypeError,
798800
}

src/lang/vm_map.zig

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -168,8 +168,11 @@ pub fn mapSet(ctx: VMContext, container: Value, key: Value, val: Value) !void {
168168
const items_now = try vms.asMapSlice(container.object);
169169
@memcpy(ext[0..old_len], items_now);
170170
ext[old_len] = .{ .key = key, .value = val };
171-
if (container.object.* == .map_managed) ctx.hs.freeManagedSlice(MapEntry, container.object.map_managed);
171+
// Publish before freeing the old slice so paranoia doesn't see a live
172+
// object (container.object) still pointing at the bytes being freed.
173+
const old_to_free: ?[]MapEntry = if (container.object.* == .map_managed) container.object.map_managed else null;
172174
container.object.* = .{ .map_managed = ext[0..new_len] };
175+
if (old_to_free) |old| ctx.hs.freeManagedSlice(MapEntry, old);
173176
if (new_len > 8) {
174177
const bcount = mapBucketsForCount(new_len);
175178
const buckets = try vmgc.vmAllocManagedSlice(ctx, i32, bcount);

0 commit comments

Comments
 (0)