authorgravatar for mail@isaacfreund.comIsaac Freund <mail@isaacfreund.com> 2026-07-04 13:41:19+02:00
committergravatar for mail@isaacfreund.comIsaac Freund <mail@isaacfreund.com> 2026-07-08 11:49:01+02:00
loge054442e2371b0176c14ff740d78607d078ca9fb
tree5469c4564c8d4b0a020b3cc444affb64fdd66022
parent203e8279539220db84823bb79671c5c6c7d1065f
signaturelock-open Commit is signed but in an unrecognized format.

grammar: actually forbid chained compare ops

Currently the grammar doesn't forbid chained compare ops, see the new test case which now passes.

3 files changed, 16 insertions(+), 13 deletions(-)

doc/langref/grammar.peg+1-1
...@@ -126,7 +126,7 @@ BoolOrExpr <- BoolAndExpr (OrOp BoolAndExpr)* !OrOp...@@ -126,7 +126,7 @@ BoolOrExpr <- BoolAndExpr (OrOp BoolAndExpr)* !OrOp
126126
127BoolAndExpr <- CompareExpr (AndOp CompareExpr)* !AndOp127BoolAndExpr <- CompareExpr (AndOp CompareExpr)* !AndOp
128128
129CompareExpr <- BitwiseExpr (CompareOp BitwiseExpr / !CompareOp)129CompareExpr <- BitwiseExpr (CompareOp BitwiseExpr)? !CompareOp
130130
131BitwiseExpr <- BitShiftExpr (BitwiseOp BitShiftExpr)* !BitwiseOp131BitwiseExpr <- BitShiftExpr (BitwiseOp BitShiftExpr)* !BitwiseOp
132132
lib/std/zig/parser_fuzz.zig+5
...@@ -140,6 +140,11 @@ test "bin op at end of file" {...@@ -140,6 +140,11 @@ test "bin op at end of file" {
140 );140 );
141}141}
142142
143// Found using AFL++
144test "resume block chained compare ops" {
145 try checkAgainstOracle("test{resume{0 > 0;} > 0 > 0;}");
146}
147
143fn checkAgainstOracle(source: [:0]const u8) !void {148fn checkAgainstOracle(source: [:0]const u8) !void {
144 var fba_buf: [1 << 18]u8 = undefined;149 var fba_buf: [1 << 18]u8 = undefined;
145 var fba: std.heap.FixedBufferAllocator = .init(&fba_buf);150 var fba: std.heap.FixedBufferAllocator = .init(&fba_buf);
lib/std/zig/parser_generated_oracle.zig+10-12
...@@ -639,18 +639,16 @@ const Parser = struct {...@@ -639,18 +639,16 @@ const Parser = struct {
639 pub fn parseCompareExpr(p: *Parser) Error!bool {639 pub fn parseCompareExpr(p: *Parser) Error!bool {
640 return blk_0: {640 return blk_0: {
641 const pos_0 = p.i;641 const pos_0 = p.i;
642 if (try p.parseBitwiseExpr() and blk_2: {642 if (try p.parseBitwiseExpr() and (blk_3: {
643 const pos_2 = p.i;643 const pos_3 = p.i;
644 if (try p.parseCompareOp() and try p.parseBitwiseExpr()) break :blk_2 true;644 if (try p.parseCompareOp() and try p.parseBitwiseExpr()) break :blk_3 true;
645 p.i = pos_2;645 p.i = pos_3;
646 if (blk_3: {646 break :blk_3 false;
647 const pos_3 = p.i;647 } or true) and blk_1: {
648 const match_3 = try p.parseCompareOp();648 const pos_1 = p.i;
649 p.i = pos_3;649 const match_1 = try p.parseCompareOp();
650 break :blk_3 !match_3;650 p.i = pos_1;
651 }) break :blk_2 true;651 break :blk_1 !match_1;
652 p.i = pos_2;
653 break :blk_2 false;
654 }) break :blk_0 true;652 }) break :blk_0 true;
655 p.i = pos_0;653 p.i = pos_0;
656 break :blk_0 false;654 break :blk_0 false;