Commit 1b87d45494

Matthew Borkowski <matthew.h.borkowski@gmail.com>
2021-05-07 02:33:17
fix a double free in parse when duplicate_field_behavior is UseLast and a leak in parse when allocating a single item
1 parent ace5714
Changed files (1)
lib
lib/std/json.zig
@@ -1571,6 +1571,7 @@ fn parseInternal(comptime T: type, token: Token, tokens: *TokenStream, options:
                                         return error.DuplicateJSONField;
                                     } else if (options.duplicate_field_behavior == .UseLast) {
                                         parseFree(field.field_type, @field(r, field.name), options);
+                                        fields_seen[i] = false;
                                     }
                                 }
                                 if (field.is_comptime) {
@@ -1642,6 +1643,7 @@ fn parseInternal(comptime T: type, token: Token, tokens: *TokenStream, options:
             switch (ptrInfo.size) {
                 .One => {
                     const r: T = try allocator.create(ptrInfo.child);
+                    errdefer allocator.destroy(r);
                     r.* = try parseInternal(ptrInfo.child, token, tokens, options);
                     return r;
                 },
@@ -1988,6 +1990,24 @@ test "parse into struct with misc fields" {
     try testing.expectEqual(T.Union{ .float = 100000 }, r.a_union);
 }
 
+test "parse into struct with duplicate field" {
+    // allow allocator to detect double frees by keeping bucket in use
+    const ballast = try testing.allocator.alloc(u64, 1);
+    defer testing.allocator.free(ballast);
+
+    const options = ParseOptions{ 
+        .allocator = testing.allocator,
+        .duplicate_field_behavior = .UseLast,
+    };
+    const str = "{ \"a\": 1, \"a\": 0.25 }";
+    
+    const T1 = struct { a: *u64 };
+    testing.expectError(error.UnexpectedToken, parse(T1, &TokenStream.init(str), options));
+
+    const T2 = struct { a: f64 };
+    testing.expectEqual(T2{ .a = 0.25 }, try parse(T2, &TokenStream.init(str), options));
+}
+
 /// A non-stream JSON parser which constructs a tree of Value's.
 pub const Parser = struct {
     allocator: *Allocator,