Fix critical segfault: add bounds checking to parser diag buffer

The self-hosted compiler crashed with SIGSEGV when processing files
that generated >=256 parser diagnostics (e.g. truncated source files).
The parser allocated a fixed-size diag buffer of 256 entries, but
parserExpect, parserExpectIdentOrKeyword, and parserEmitDiag wrote
into it without checking bounds. Once diagCount exceeded 256, writes
overflowed into adjacent heap objects (Decl structs), corrupting
their kind/childDecl2 fields and causing crashes during AST traversal.

This fix adds bounds checks to all three sites so excess diagnostics
are silently dropped rather than corrupting memory. The file size
threshold (7037 vs 7062 bytes) was a red herring — it determined
how many parser errors were generated before EOF.

Closes: selfhost segfault on 250+ line files
This commit is contained in:
2026-06-02 01:31:18 +03:00
parent 975cc347d0
commit d1160ca5d1
+12 -8
View File
@@ -78,10 +78,12 @@ func parserExpect(p: *Parser, kind: int, msg: String) -> LexToken {
return parserAdvance(p); return parserAdvance(p);
} }
let tok: LexToken = parserCurToken(p); let tok: LexToken = parserCurToken(p);
p.diags[p.diagCount] = ParserDiag { if p.diagCount < 256 {
line: tok.line, column: tok.column, message: msg p.diags[p.diagCount] = ParserDiag {
}; line: tok.line, column: tok.column, message: msg
p.diagCount = p.diagCount + 1; };
p.diagCount = p.diagCount + 1;
}
return tok; return tok;
} }
@@ -103,10 +105,12 @@ func parserExpectIdentOrKeyword(p: *Parser, msg: String) -> LexToken {
if tok.kind == tkIdent || parserIsKeyword(tok.kind) { if tok.kind == tkIdent || parserIsKeyword(tok.kind) {
return parserAdvance(p); return parserAdvance(p);
} }
p.diags[p.diagCount] = ParserDiag { if p.diagCount < 256 {
line: tok.line, column: tok.column, message: msg p.diags[p.diagCount] = ParserDiag {
}; line: tok.line, column: tok.column, message: msg
p.diagCount = p.diagCount + 1; };
p.diagCount = p.diagCount + 1;
}
return tok; return tok;
} }