selfhost: fix parser infinite loop + lexer token limit
- Parser_Parse: add beforePos safeguard to skip unrecognized tokens instead of looping forever when parserParseDecl returns null - Lexer: increase maxTokens 4096 -> 32768; add explicit break on limit - CLI: null-check ReadFile result before String_Eq - Nim CLI: add -O2 to cc invocation for faster self-hosted builds
This commit is contained in:
@@ -106,7 +106,7 @@ func Cli_Compile(source: String, sourceName: String) -> String {
|
|||||||
|
|
||||||
func Cli_Build(srcPath: String, outPath: String) -> int {
|
func Cli_Build(srcPath: String, outPath: String) -> int {
|
||||||
let source: String = ReadFile(srcPath);
|
let source: String = ReadFile(srcPath);
|
||||||
if String_Eq(source, "") || !FileExists(srcPath) {
|
if source == null as String || String_Eq(source, "") || !FileExists(srcPath) {
|
||||||
Print("Error: cannot read source file: ");
|
Print("Error: cannot read source file: ");
|
||||||
PrintLine(srcPath);
|
PrintLine(srcPath);
|
||||||
return 1;
|
return 1;
|
||||||
@@ -142,7 +142,7 @@ func Cli_Check(srcPath: String) -> int {
|
|||||||
Print("Check: ");
|
Print("Check: ");
|
||||||
PrintLine(srcPath);
|
PrintLine(srcPath);
|
||||||
let source: String = ReadFile(srcPath);
|
let source: String = ReadFile(srcPath);
|
||||||
if String_Eq(source, "") {
|
if source == null as String || String_Eq(source, "") {
|
||||||
PrintLine("Error: cannot read source file");
|
PrintLine("Error: cannot read source file");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ func Lex_IsIdentChar(c: uint32) -> bool {
|
|||||||
// Lexer state
|
// Lexer state
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
const maxTokens: int = 4096;
|
const maxTokens: int = 32768;
|
||||||
const maxDiags: int = 128;
|
const maxDiags: int = 128;
|
||||||
|
|
||||||
struct LexerDiag {
|
struct LexerDiag {
|
||||||
@@ -587,7 +587,6 @@ func lexNextToken(lex: *Lexer) {
|
|||||||
lexEmitToken(lex, tkEndOfFile);
|
lexEmitToken(lex, tkEndOfFile);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let c: uint32 = lexPeek(lex, 0);
|
let c: uint32 = lexPeek(lex, 0);
|
||||||
|
|
||||||
if c == 10 { // \n
|
if c == 10 { // \n
|
||||||
@@ -673,6 +672,10 @@ func Lexer_Tokenize(source: String) -> *Lexer {
|
|||||||
|
|
||||||
while true {
|
while true {
|
||||||
lexNextToken(lex);
|
lexNextToken(lex);
|
||||||
|
if lex.tokenCount >= maxTokens {
|
||||||
|
lexEmitDiag(lex, "too many tokens");
|
||||||
|
break;
|
||||||
|
}
|
||||||
if lex.tokens[lex.tokenCount - 1].kind == tkEndOfFile {
|
if lex.tokens[lex.tokenCount - 1].kind == tkEndOfFile {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1195,12 +1195,17 @@ func Parser_Parse(tokens: *LexToken, tokenCount: int) -> *Module {
|
|||||||
discard parserAdvance(p);
|
discard parserAdvance(p);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
let beforePos: int = p.pos;
|
||||||
let decl: *Decl = parserParseDecl(p);
|
let decl: *Decl = parserParseDecl(p);
|
||||||
if decl != null as *Decl {
|
if decl != null as *Decl {
|
||||||
decl.childDecl2 = mod.firstItem; // push front
|
decl.childDecl2 = mod.firstItem; // push front
|
||||||
mod.firstItem = decl;
|
mod.firstItem = decl;
|
||||||
mod.itemCount = mod.itemCount + 1;
|
mod.itemCount = mod.itemCount + 1;
|
||||||
}
|
}
|
||||||
|
// Infinite-loop safeguard: if no progress, skip token
|
||||||
|
if p.pos == beforePos {
|
||||||
|
discard parserAdvance(p);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return mod;
|
return mod;
|
||||||
|
|||||||
+1
-1
@@ -536,7 +536,7 @@ proc cmdBuild*(args: seq[string], opts: GlobalOptions): int =
|
|||||||
# Compile with cc
|
# Compile with cc
|
||||||
let outputName = if man.name != "": man.name else: "bux_out"
|
let outputName = if man.name != "": man.name else: "bux_out"
|
||||||
let outputFile = buildDir / outputName
|
let outputFile = buildDir / outputName
|
||||||
let ccCmd = &"cc -pthread -o {outputFile} {cFile} {runtimeDst} {ioDst} -lm 2>&1"
|
let ccCmd = &"cc -O2 -pthread -o {outputFile} {cFile} {runtimeDst} {ioDst} -lm 2>&1"
|
||||||
if opts.verbose:
|
if opts.verbose:
|
||||||
printInfo(&"running: {ccCmd}", useColor)
|
printInfo(&"running: {ccCmd}", useColor)
|
||||||
let (output, exitCode) = execCmdEx(ccCmd)
|
let (output, exitCode) = execCmdEx(ccCmd)
|
||||||
|
|||||||
+2
-2
@@ -106,7 +106,7 @@ func Cli_Compile(source: String, sourceName: String) -> String {
|
|||||||
|
|
||||||
func Cli_Build(srcPath: String, outPath: String) -> int {
|
func Cli_Build(srcPath: String, outPath: String) -> int {
|
||||||
let source: String = ReadFile(srcPath);
|
let source: String = ReadFile(srcPath);
|
||||||
if String_Eq(source, "") || !FileExists(srcPath) {
|
if source == null as String || String_Eq(source, "") || !FileExists(srcPath) {
|
||||||
Print("Error: cannot read source file: ");
|
Print("Error: cannot read source file: ");
|
||||||
PrintLine(srcPath);
|
PrintLine(srcPath);
|
||||||
return 1;
|
return 1;
|
||||||
@@ -142,7 +142,7 @@ func Cli_Check(srcPath: String) -> int {
|
|||||||
Print("Check: ");
|
Print("Check: ");
|
||||||
PrintLine(srcPath);
|
PrintLine(srcPath);
|
||||||
let source: String = ReadFile(srcPath);
|
let source: String = ReadFile(srcPath);
|
||||||
if String_Eq(source, "") {
|
if source == null as String || String_Eq(source, "") {
|
||||||
PrintLine("Error: cannot read source file");
|
PrintLine("Error: cannot read source file");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|||||||
+5
-2
@@ -42,7 +42,7 @@ func Lex_IsIdentChar(c: uint32) -> bool {
|
|||||||
// Lexer state
|
// Lexer state
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
const maxTokens: int = 4096;
|
const maxTokens: int = 32768;
|
||||||
const maxDiags: int = 128;
|
const maxDiags: int = 128;
|
||||||
|
|
||||||
struct LexerDiag {
|
struct LexerDiag {
|
||||||
@@ -587,7 +587,6 @@ func lexNextToken(lex: *Lexer) {
|
|||||||
lexEmitToken(lex, tkEndOfFile);
|
lexEmitToken(lex, tkEndOfFile);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let c: uint32 = lexPeek(lex, 0);
|
let c: uint32 = lexPeek(lex, 0);
|
||||||
|
|
||||||
if c == 10 { // \n
|
if c == 10 { // \n
|
||||||
@@ -673,6 +672,10 @@ func Lexer_Tokenize(source: String) -> *Lexer {
|
|||||||
|
|
||||||
while true {
|
while true {
|
||||||
lexNextToken(lex);
|
lexNextToken(lex);
|
||||||
|
if lex.tokenCount >= maxTokens {
|
||||||
|
lexEmitDiag(lex, "too many tokens");
|
||||||
|
break;
|
||||||
|
}
|
||||||
if lex.tokens[lex.tokenCount - 1].kind == tkEndOfFile {
|
if lex.tokens[lex.tokenCount - 1].kind == tkEndOfFile {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1195,12 +1195,17 @@ func Parser_Parse(tokens: *LexToken, tokenCount: int) -> *Module {
|
|||||||
discard parserAdvance(p);
|
discard parserAdvance(p);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
let beforePos: int = p.pos;
|
||||||
let decl: *Decl = parserParseDecl(p);
|
let decl: *Decl = parserParseDecl(p);
|
||||||
if decl != null as *Decl {
|
if decl != null as *Decl {
|
||||||
decl.childDecl2 = mod.firstItem; // push front
|
decl.childDecl2 = mod.firstItem; // push front
|
||||||
mod.firstItem = decl;
|
mod.firstItem = decl;
|
||||||
mod.itemCount = mod.itemCount + 1;
|
mod.itemCount = mod.itemCount + 1;
|
||||||
}
|
}
|
||||||
|
// Infinite-loop safeguard: if no progress, skip token
|
||||||
|
if p.pos == beforePos {
|
||||||
|
discard parserAdvance(p);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return mod;
|
return mod;
|
||||||
|
|||||||
Reference in New Issue
Block a user