authorgravatar for matthew.h.borkowski@gmail.comMatthew Borkowski <matthew.h.borkowski@gmail.com> 2021-05-06 20:33:17-04:00
committergravatar for mail@isaacfreund.comIsaac Freund <mail@isaacfreund.com> 2021-05-11 22:54:02+02:00
log1b87d4549468d37d8673b2e69611e0f2688ed6c5
treeb4950be704fe3dec9bb99b2e69e48c685ab870da
parentace5714551da16b541d8015e97a2fe32a7a1cf76

fix a double free in parse when duplicate_field_behavior is UseLast and a leak in parse when allocating a single item


1 files changed, 20 insertions(+), 0 deletions(-)

lib/std/json.zig+20
...@@ -1571,6 +1571,7 @@ fn parseInternal(comptime T: type, token: Token, tokens: *TokenStream, options:...@@ -1571,6 +1571,7 @@ fn parseInternal(comptime T: type, token: Token, tokens: *TokenStream, options:
1571 return error.DuplicateJSONField;1571 return error.DuplicateJSONField;
1572 } else if (options.duplicate_field_behavior == .UseLast) {1572 } else if (options.duplicate_field_behavior == .UseLast) {
1573 parseFree(field.field_type, @field(r, field.name), options);1573 parseFree(field.field_type, @field(r, field.name), options);
1574 fields_seen[i] = false;
1574 }1575 }
1575 }1576 }
1576 if (field.is_comptime) {1577 if (field.is_comptime) {
...@@ -1642,6 +1643,7 @@ fn parseInternal(comptime T: type, token: Token, tokens: *TokenStream, options:...@@ -1642,6 +1643,7 @@ fn parseInternal(comptime T: type, token: Token, tokens: *TokenStream, options:
1642 switch (ptrInfo.size) {1643 switch (ptrInfo.size) {
1643 .One => {1644 .One => {
1644 const r: T = try allocator.create(ptrInfo.child);1645 const r: T = try allocator.create(ptrInfo.child);
1646 errdefer allocator.destroy(r);
1645 r.* = try parseInternal(ptrInfo.child, token, tokens, options);1647 r.* = try parseInternal(ptrInfo.child, token, tokens, options);
1646 return r;1648 return r;
1647 },1649 },
...@@ -1988,6 +1990,24 @@ test "parse into struct with misc fields" {...@@ -1988,6 +1990,24 @@ test "parse into struct with misc fields" {
1988 try testing.expectEqual(T.Union{ .float = 100000 }, r.a_union);1990 try testing.expectEqual(T.Union{ .float = 100000 }, r.a_union);
1989}1991}
19901992
1993test "parse into struct with duplicate field" {
1994 // allow allocator to detect double frees by keeping bucket in use
1995 const ballast = try testing.allocator.alloc(u64, 1);
1996 defer testing.allocator.free(ballast);
1997
1998 const options = ParseOptions{
1999 .allocator = testing.allocator,
2000 .duplicate_field_behavior = .UseLast,
2001 };
2002 const str = "{ \"a\": 1, \"a\": 0.25 }";
2003
2004 const T1 = struct { a: *u64 };
2005 testing.expectError(error.UnexpectedToken, parse(T1, &TokenStream.init(str), options));
2006
2007 const T2 = struct { a: f64 };
2008 testing.expectEqual(T2{ .a = 0.25 }, try parse(T2, &TokenStream.init(str), options));
2009}
2010
1991/// A non-stream JSON parser which constructs a tree of Value's.2011/// A non-stream JSON parser which constructs a tree of Value's.
1992pub const Parser = struct {2012pub const Parser = struct {
1993 allocator: *Allocator,2013 allocator: *Allocator,