Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(sem): nimsuggest crashing for ill-formed AST #939

Merged
merged 20 commits into from
Oct 5, 2023
Merged
Show file tree
Hide file tree
Changes from 12 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 33 additions & 6 deletions compiler/front/msgs.nim
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,12 @@ from compiler/ast/reports_sem import SemReport
export InstantiationInfo
export TErrorHandling

proc handleReport*(
conf: ConfigRef,
r: Report,
reportFrom: InstantiationInfo,
eh: TErrorHandling = doNothing) {.noinline.}

template toStdOrrKind(stdOrr): untyped =
if stdOrr == stdout: stdOrrStdout else: stdOrrStderr

Expand Down Expand Up @@ -600,18 +606,20 @@ proc report*(conf: ConfigRef, node: PNode): TErrorHandling =
assert node.kind == nkError
return conf.report(conf.astDiagToLegacyReport(conf, node.diag))

proc fillReportAndHandleVmReport(c: ConfigRef, r: var Report, reportFrom: InstantiationInfo) =
bung87 marked this conversation as resolved.
Show resolved Hide resolved
r.reportFrom = toReportLineInfo(reportFrom)
if r.category in { repSem, repVM } and r.location.isSome():
r.context = c.getContext(r.location.get())
if r.category == repVM and r.vmReport.trace != nil:
bung87 marked this conversation as resolved.
Show resolved Hide resolved
handleReport(c, wrap(r.vmReport.trace[]), reportFrom)

proc handleReport*(
conf: ConfigRef,
r: Report,
reportFrom: InstantiationInfo,
eh: TErrorHandling = doNothing) {.noinline.} =
var rep = r
rep.reportFrom = toReportLineInfo(reportFrom)
if rep.category in { repSem, repVM } and rep.location.isSome():
rep.context = conf.getContext(rep.location.get())

if rep.category == repVM and rep.vmReport.trace != nil:
handleReport(conf, wrap(rep.vmReport.trace[]), reportFrom)
fillReportAndHandleVmReport(conf, rep, reportFrom)
bung87 marked this conversation as resolved.
Show resolved Hide resolved

let
userAction = conf.report(rep)
Expand Down Expand Up @@ -654,6 +662,25 @@ template globalReport*(conf: ConfigRef, report: ReportTypes) =
handleReport(
conf, wrap(report, instLoc()), instLoc(), doRaise)

proc reportAndForceRaise*(
bung87 marked this conversation as resolved.
Show resolved Hide resolved
conf: ConfigRef, r: Report, reportFrom: InstantiationInfo) =
## Similar to `handleReport`, but, unless overridden with aborting
## (`doAbort`) by the structured report hook, always raises a recoverable
## error.
var rep = r
fillReportAndHandleVmReport(conf, rep, reportFrom)
bung87 marked this conversation as resolved.
Show resolved Hide resolved

case conf.report(rep)
of doAbort:
quit 1
of doRaise, doDefault, doNothing:
raiseRecoverableError("report")

template reportAndForceRaise*(
conf: ConfigRef; info: TLineInfo, report: ReportTypes) =
reportAndForceRaise(
conf, wrap(report, instLoc(), info), instLoc())

template localReport*(conf: ConfigRef; info: TLineInfo, report: ReportTypes) =
{.line.}:
handleReport(
Expand Down
4 changes: 2 additions & 2 deletions compiler/sem/semdata.nim
Original file line number Diff line number Diff line change
Expand Up @@ -1065,13 +1065,13 @@ proc markIndirect*(c: PContext, s: PSym) {.inline.} =

proc checkSonsLen*(n: PNode, length: int; conf: ConfigRef) =
if n.len != length:
conf.globalReport(n.info, reportAst(
conf.reportAndForceRaise(n.info, reportAst(
rsemIllformedAst, n,
str = "Expected $1 elements, but found $2" % [$length, $n.len]))

proc checkMinSonsLen*(n: PNode, length: int; conf: ConfigRef) =
if n.len < length:
conf.globalReport(n.info, reportAst(
conf.reportAndForceRaise(n.info, reportAst(
rsemIllformedAst, n,
str = "Expected at least $1 elements, but found $2" % [$length, $n.len]))

Expand Down
20 changes: 20 additions & 0 deletions nimsuggest/tests/terror_handling.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Ensure that AST not having the correct number of nodes doesn't cause
# crashes. This a regression test for `checkSonsMinLen` and
# `checkSonsLen` not aborting analysis.

import std/macros

macro t1(): untyped =
result = newNimNode(nnkForStmt)
result.add(ident("i"))
result.add newNimNode(nnkCall)
result.add nnkDiscardStmt.newTree(newEmptyNode())
bung87 marked this conversation as resolved.
Show resolved Hide resolved

t1()

#[!]#
discard """
$nimsuggest --tester $file
>chk $1
chk;;skUnknown;;;;Error;;$file;;10;;23;;"illformed AST: ()";;0
"""
Loading