Report memory leaks when using std.testing.allocator

Fix leaks in storage bottle
This commit is contained in:
Karl Seguin
2025-02-08 20:08:29 +08:00
parent 2c4661a250
commit 4229b1d2a4
2 changed files with 31 additions and 18 deletions

View File

@@ -223,8 +223,14 @@ pub fn main() !void {
try parser.init(); try parser.init();
defer parser.deinit(); defer parser.deinit();
std.testing.allocator_instance = .{};
try test_fn.func(); try test_fn.func();
std.debug.print("{s}\tOK\n", .{test_fn.name});
if (std.testing.allocator_instance.deinit() == .leak) {
std.debug.print("======Memory Leak: {s}======\n", .{test_fn.name});
} else {
std.debug.print("{s}\tOK\n", .{test_fn.name});
}
} }
} }
} }

View File

@@ -149,20 +149,22 @@ pub const Bottle = struct {
} }
pub fn _setItem(self: *Bottle, k: []const u8, v: []const u8) !void { pub fn _setItem(self: *Bottle, k: []const u8, v: []const u8) !void {
const old = self.map.get(k); const gop = self.map.getOrPut(self.alloc, k) catch |e| {
if (old != null and std.mem.eql(u8, v, old.?)) return;
// owns k and v by copying them.
const kk = try self.alloc.dupe(u8, k);
errdefer self.alloc.free(kk);
const vv = try self.alloc.dupe(u8, v);
errdefer self.alloc.free(vv);
self.map.put(self.alloc, kk, vv) catch |e| {
log.debug("set item: {any}", .{e}); log.debug("set item: {any}", .{e});
return DOMError.QuotaExceeded; return DOMError.QuotaExceeded;
}; };
if (gop.found_existing == false) {
gop.key_ptr.* = try self.alloc.dupe(u8, k);
gop.value_ptr.* = try self.alloc.dupe(u8, v);
return;
}
if (std.mem.eql(u8, v, gop.value_ptr.*) == false) {
self.alloc.free(gop.value_ptr.*);
gop.value_ptr.* = try self.alloc.dupe(u8, v);
}
// > Broadcast this with key, oldValue, and value. // > Broadcast this with key, oldValue, and value.
// https://html.spec.whatwg.org/multipage/webstorage.html#the-storageevent-interface // https://html.spec.whatwg.org/multipage/webstorage.html#the-storageevent-interface
// //
@@ -175,8 +177,10 @@ pub const Bottle = struct {
} }
pub fn _removeItem(self: *Bottle, k: []const u8) !void { pub fn _removeItem(self: *Bottle, k: []const u8) !void {
const old = self.map.fetchRemove(k); if (self.map.fetchRemove(k)) |kv| {
if (old == null) return; self.alloc.free(kv.key);
self.alloc.free(kv.value);
}
// > Broadcast this with key, oldValue, and null. // > Broadcast this with key, oldValue, and null.
// https://html.spec.whatwg.org/multipage/webstorage.html#the-storageevent-interface // https://html.spec.whatwg.org/multipage/webstorage.html#the-storageevent-interface
@@ -235,14 +239,17 @@ test "storage bottle" {
var bottle = Bottle.init(std.testing.allocator); var bottle = Bottle.init(std.testing.allocator);
defer bottle.deinit(); defer bottle.deinit();
try std.testing.expect(0 == bottle.get_length()); try std.testing.expectEqual(0, bottle.get_length());
try std.testing.expect(null == bottle._getItem("foo")); try std.testing.expectEqual(null, bottle._getItem("foo"));
try bottle._setItem("foo", "bar"); try bottle._setItem("foo", "bar");
try std.testing.expect(std.mem.eql(u8, "bar", bottle._getItem("foo").?)); try std.testing.expectEqualStrings("bar", bottle._getItem("foo").?);
try bottle._setItem("foo", "other");
try std.testing.expectEqualStrings("other", bottle._getItem("foo").?);
try bottle._removeItem("foo"); try bottle._removeItem("foo");
try std.testing.expect(0 == bottle.get_length()); try std.testing.expectEqual(0, bottle.get_length());
try std.testing.expect(null == bottle._getItem("foo")); try std.testing.expectEqual(null, bottle._getItem("foo"));
} }