From db9d8003b074cb6d150f7ece467f29006ccefde7 Mon Sep 17 00:00:00 2001 From: Jake Leahy Date: Wed, 20 Dec 2023 03:27:24 +1100 Subject: Don't crash for invalid toplevel parseStmt/Expr calls (#23089) This code will crash `check`/`nimsuggest` since the `ra` register is uninitialised ```nim import macros static: discard parseExpr("'") ``` Now it assigns an empty node so that it has something Testament changes were so I could properly write a test. It would pass even with a segfault since it could find the error --- compiler/vm.nim | 3 +++ testament/testament.nim | 13 +++++++++---- tests/macros/tfail_parse.nim | 15 +++++++++++++++ 3 files changed, 27 insertions(+), 4 deletions(-) create mode 100644 tests/macros/tfail_parse.nim diff --git a/compiler/vm.nim b/compiler/vm.nim index 88419d5dd..d74a64908 100644 --- a/compiler/vm.nim +++ b/compiler/vm.nim @@ -1925,6 +1925,8 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg = proc (conf: ConfigRef; info: TLineInfo; msg: TMsgKind; arg: string) = if error.len == 0 and msg <= errMax: error = formatMsg(conf, info, msg, arg)) + + regs[ra].node = newNode(nkEmpty) if error.len > 0: c.errorFlag = error elif ast.len != 1: @@ -1942,6 +1944,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg = error = formatMsg(conf, info, msg, arg)) if error.len > 0: c.errorFlag = error + regs[ra].node = newNode(nkEmpty) else: regs[ra].node = ast of opcQueryErrorFlag: diff --git a/testament/testament.nim b/testament/testament.nim index 5f443ffba..e0a200e29 100644 --- a/testament/testament.nim +++ b/testament/testament.nim @@ -193,7 +193,6 @@ proc callNimCompiler(cmdTemplate, filename, options, nimcache: string, foundSuccessMsg = true elif not running(p): break - close(p) result.msg = "" result.file = "" result.output = "" @@ -201,8 +200,9 @@ proc callNimCompiler(cmdTemplate, filename, options, nimcache: string, result.column = 0 result.err = reNimcCrash - let exitCode = p.peekExitCode - case exitCode + result.exitCode = p.peekExitCode + close p + case result.exitCode of 0: if foundErrorMsg: result.debugInfo.add " compiler exit code was 0 but some Error's were found." @@ -214,7 +214,7 @@ proc callNimCompiler(cmdTemplate, filename, options, nimcache: string, if foundSuccessMsg: result.debugInfo.add " compiler exit code was 1 but no `isSuccess` was true." else: - result.debugInfo.add " expected compiler exit code 0 or 1, got $1." % $exitCode + result.debugInfo.add " expected compiler exit code 0 or 1, got $1." % $result.exitCode if err =~ pegLineError: result.file = extractFilename(matches[0]) @@ -521,7 +521,12 @@ proc testSpecHelper(r: var TResults, test: var TTest, expected: TSpec, r.addResult(test, target, extraOptions, expected.output, bufB, reOutputsDiffer) compilerOutputTests(test, target, extraOptions, given, expected, r) of actionReject: + # Make sure its the compiler rejecting and not the system (e.g. segfault) cmpMsgs(r, expected, given, test, target, extraOptions) + if given.exitCode != QuitFailure: + r.addResult(test, target, extraOptions, "exitcode: " & $QuitFailure, + "exitcode: " & $given.exitCode & "\n\nOutput:\n" & + given.nimout, reExitcodesDiffer) proc targetHelper(r: var TResults, test: TTest, expected: TSpec, extraOptions: string) = for target in expected.targets: diff --git a/tests/macros/tfail_parse.nim b/tests/macros/tfail_parse.nim new file mode 100644 index 000000000..1925f2b69 --- /dev/null +++ b/tests/macros/tfail_parse.nim @@ -0,0 +1,15 @@ +discard """ +action: "reject" +cmd: "nim check $file" +errormsg: "expected expression, but got multiple statements [ValueError]" +file: "macros.nim" +""" + +import macros +static: + discard parseStmt("'") + discard parseExpr("'") + discard parseExpr(""" +proc foo() +proc foo() = discard +""") -- cgit 1.4.1-2-gfad0