From b0738ef3e0354765b5aa1713d6313c8606c52f41 Mon Sep 17 00:00:00 2001 From: Isaac Freund Date: Mon, 6 Jul 2026 15:20:25 +0200 Subject: [PATCH] parser: warn on non-final varargs before further parsing To prevent the fuzzer from being able to reach stack overflows, we need to give an error for non-final varargs (...) before parsing the next argument. --- lib/std/zig/Parse.zig | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/lib/std/zig/Parse.zig b/lib/std/zig/Parse.zig index 61213ba90205cd847424d637438e0bdbd863fbdc..bb75a31af95eda7cbd138f4b7ffe509fafc45d15 100644 --- a/lib/std/zig/Parse.zig +++ b/lib/std/zig/Parse.zig @@ -3371,6 +3371,7 @@ fn expectContainerDeclAuto(p: *Parse) !Node.Index { /// Give a helpful error message for those transitioning from /// C's 'struct Foo {};' to Zig's 'const Foo = struct {};'. fn parseCStyleContainer(p: *Parse) Error!bool { + if (!p.recover) return false; const main_token = p.tok_i; switch (p.tokenTag(p.tok_i)) { .keyword_enum, .keyword_union, .keyword_struct => {}, @@ -3436,10 +3437,13 @@ fn parseParamDeclList(p: *Parse) !SmallSpan { _ = try p.expectToken(.l_paren); const scratch_top = p.scratch.items.len; defer p.scratch.shrinkRetainingCapacity(scratch_top); - var varargs: union(enum) { none, seen, nonfinal: TokenIndex } = .none; + var varargs: enum { none, seen, err } = .none; while (true) { if (p.eatToken(.r_paren)) |_| break; - if (varargs == .seen) varargs = .{ .nonfinal = p.tok_i }; + if (varargs == .seen) { + try p.warnMsg(.{ .tag = .varargs_nonfinal, .token = p.tok_i }); + varargs = .err; + } const opt_param = try p.expectParamDecl(); if (opt_param) |param| { try p.scratch.append(p.gpa, param); @@ -3457,9 +3461,6 @@ fn parseParamDeclList(p: *Parse) !SmallSpan { else => try p.warn(.expected_comma_after_param), } } - if (varargs == .nonfinal) { - try p.warnMsg(.{ .tag = .varargs_nonfinal, .token = varargs.nonfinal }); - } const params = p.scratch.items[scratch_top..]; return switch (params.len) { 0 => .{ .zero_or_one = .none }, -- 2.54.0