From 0a01fe2bc6748b5fa2b03cebdcaae0e655501ad4 Mon Sep 17 00:00:00 2001 From: Jan Bessai Date: Fri, 2 May 2025 18:17:28 +0200 Subject: [PATCH] std.zig.Parse: fix and test off-by one in unreserveNode --- lib/std/zig/Parse.zig | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/lib/std/zig/Parse.zig b/lib/std/zig/Parse.zig index facb74a006b5389a61bcc6a089234028fa0b1128..106b07f5ed058ec43231a5f1f4e5752ab2d6a8dc 100644 --- a/lib/std/zig/Parse.zig +++ b/lib/std/zig/Parse.zig @@ -92,7 +92,7 @@ fn reserveNode(p: *Parse, tag: Ast.Node.Tag) !usize { } fn unreserveNode(p: *Parse, node_index: usize) void { - if (p.nodes.len == node_index) { + if (p.nodes.len == node_index + 1) { p.nodes.resize(p.gpa, p.nodes.len - 1) catch unreachable; } else { // There is zombie node left in the tree, let's make it as inoffensive as possible @@ -3417,3 +3417,22 @@ const Token = std.zig.Token; test { _ = @import("parser_test.zig"); } + +test "unreserving a freshly reserved AST node must not create zombies" { + const gpa = std.testing.allocator; + var parser: Parse = .{ + .gpa = gpa, + .nodes = .empty, + .errors = .empty, + .extra_data = .empty, + .scratch = .empty, + .source = "", + .tok_i = 0, + .tokens = undefined, + .recover = false, + }; + defer parser.nodes.deinit(gpa); + const last = try parser.reserveNode(.@"try"); + parser.unreserveNode(last); + try std.testing.expectEqual(parser.nodes.len, 0); +} -- 2.54.0