Produced with LLM assistance.

build_relations() in usr.bin/yacc/lalr.c sizes 'edge' for ngotos+1
shorts:

    edge = NEW2(ngotos + 1, short);

But edge is a per-iteration scratch buffer (nedges resets at line
365), and the writes per outer iteration can reach the sum of
rhs lengths over rules sharing one lhs, which exceeds ngotos.

14-byte reproducer:

    $ cat > /tmp/min.y <<EOT
    %%
    t:t
    t:t,t:t
    EOT
    $ env MALLOC_OPTIONS=CFGJU yacc /tmp/min.y
    yacc(NNNNN) in free(): canary corrupted 0x...[4]@4/16
    Abort trap (core dumped)

Reproduced on OpenBSD 7.9 amd64, i386 and arm64.  Found by AFL++
fuzzing.  Patched yacc produces byte-identical output to stock on
every .y file in the base tree.

Index: usr.bin/yacc/lalr.c
===================================================================
--- usr.bin/yacc/lalr.c
+++ usr.bin/yacc/lalr.c
@@ -358,7 +358,8 @@ build_relations(void)
        short **new_includes;

        includes = NEW2(ngotos, short *);
-       edge = NEW2(ngotos + 1, short);
+       /* per-iteration scratch; bounded by total grammar items */
+       edge = NEW2(nitems + 1, short);
        states = NEW2(maxrhs + 1, short);

        for (i = 0; i < ngotos; i++) {

Reply via email to