Skip to content

x/tools/cmd/goyacc: panic ("ungetc - 2nd unget") on grammar file ending without a trailing newline #81182

Description

@shaggyinsomniac

cmd/goyacc: panic ("ungetc - 2nd unget") on grammar file ending without a newline

Summary

A 10-byte grammar file with no trailing newline crashes goyacc with a panic instead of
reporting a syntax error:

$ printf '%%\nS: A; B' > v2.y && goyacc -o /dev/null v2.y
panic: ungetc - 2nd unget

goroutine 1 [running]:
main.ungetrune(...)
	cmd/goyacc/yacc.go:3160
main.gettok()
	cmd/goyacc/yacc.go:990
main.setup()
	cmd/goyacc/yacc.go:656
main.main()
	cmd/goyacc/yacc.go:349

Any grammar whose last token is an identifier at EOF triggers it — e.g. %token A
followed by %% and S: A with no final newline.

Root cause

getrune keeps EOF sticky in the single-slot peekrune buffer: when peekrune == EOF
it returns EOF without clearing the slot (so EOF stays pushed back for the next
reader). But gettok's IDENTIFIER/IDENTCOLON look-ahead (yacc.go:975-992) ends by
ungetting whatever rune it consumed — including EOF. If EOF is already sitting in
peekrune (left by getword ungetting the identifier's terminator), the unget hits
the peekrune != 0 guard in ungetrune (yacc.go:3159-3161) and panics.

Fix

Ungetting EOF is a no-op — an exhausted reader returns EOF again on the next read
regardless, so behavior for well-formed files is identical:

func ungetrune(f *bufio.Reader, c rune) {
	if f != finput {
		panic("ungetc - not finput")
	}
	if c == EOF {
		return
	}
	if peekrune != 0 {
		panic("ungetc - 2nd unget")
	}
	peekrune = c
}

With the fix, the example above reports the proper illegal rule: missing semicolon or | error and exits 1, and a valid grammar compiles to identical output. I have
the patch ready with the repro cases verified (crash pre-fix, clean errors post-fix,
valid grammar byte-identical).

Duplicate check

Searched golang/go issues for "ungetc - 2nd unget" and goyacc panic reports: no hits.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    NeedsInvestigationSomeone must examine and confirm this is a valid issue and not a duplicate of an existing one.ToolsThis label describes issues relating to any tools in the x/tools repository.

    Type

    No type

    Projects

    No projects

      Milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions