Commit b42caff2a2

John Schmidt <john.schmidt.h@gmail.com>
2023-02-04 18:44:57
std.json: avoid dangling pointers in ValueTree
Closes https://github.com/ziglang/zig/issues/5229.
1 parent 73c8574
Changed files (2)
lib
lib/std/json/test.zig
@@ -2589,6 +2589,24 @@ test "parsing empty string gives appropriate error" {
     try testing.expectError(error.UnexpectedEndOfJson, testParse(arena_allocator.allocator(), ""));
 }
 
+test "parse tree should not contain dangling pointers" {
+    var arena_allocator = std.heap.ArenaAllocator.init(std.testing.allocator);
+    defer arena_allocator.deinit();
+
+    var p = json.Parser.init(arena_allocator.allocator(), false);
+    defer p.deinit();
+
+    var tree = try p.parse("[]");
+    defer tree.deinit();
+
+    // Allocation should succeed
+    var i: usize = 0;
+    while (i < 100) : (i += 1) {
+        try tree.root.Array.append(std.json.Value{ .Integer = 100 });
+    }
+    try testing.expectEqual(tree.root.Array.items.len, 100);
+}
+
 test "integer after float has proper type" {
     var arena_allocator = std.heap.ArenaAllocator.init(std.testing.allocator);
     defer arena_allocator.deinit();
lib/std/json.zig
@@ -1163,11 +1163,12 @@ const ArrayList = std.ArrayList;
 const StringArrayHashMap = std.StringArrayHashMap;
 
 pub const ValueTree = struct {
-    arena: ArenaAllocator,
+    arena: *ArenaAllocator,
     root: Value,
 
     pub fn deinit(self: *ValueTree) void {
         self.arena.deinit();
+        self.arena.child_allocator.destroy(self.arena);
     }
 };
 
@@ -1809,8 +1810,12 @@ pub const Parser = struct {
     pub fn parse(p: *Parser, input: []const u8) !ValueTree {
         var s = TokenStream.init(input);
 
-        var arena = ArenaAllocator.init(p.allocator);
+        var arena = try p.allocator.create(ArenaAllocator);
+        errdefer p.allocator.destroy(arena);
+
+        arena.* = ArenaAllocator.init(p.allocator);
         errdefer arena.deinit();
+
         const allocator = arena.allocator();
 
         while (try s.next()) |token| {