fix partially #13115 (now works for cpp; but still fails for js on openbsd) (#16167)

* fix partially #13115 properly (works for c,js,cpp,vm; still fails for js on openbsd)
* address comment: also test with -d:danger, -d:debug
This commit is contained in:
Timothee Cour 2020-12-11 01:35:05 -08:00 • committed by GitHub
commit bb1c962286
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 58 additions and 20 deletions

View file

@ -13,6 +13,8 @@
import std/private/miscdollars import std/private/miscdollars
import stacktraces import stacktraces
const noStacktraceAvailable = "No stack traceback available\n"
var var
errorMessageWriter*: (proc(msg: string) {.tags: [WriteIOEffect], benign, errorMessageWriter*: (proc(msg: string) {.tags: [WriteIOEffect], benign,
nimcall.}) nimcall.})
@ -36,6 +38,10 @@ else:
proc writeToStdErr(msg: cstring, length: int) = proc writeToStdErr(msg: cstring, length: int) =
discard MessageBoxA(nil, msg, nil, 0) discard MessageBoxA(nil, msg, nil, 0)
proc writeToStdErr(msg: string) {.inline.} =
# fix bug #13115: handles correctly '\0' unlike default implicit conversion to cstring
writeToStdErr(msg.cstring, msg.len)
proc showErrorMessage(data: cstring, length: int) {.gcsafe, raises: [].} = proc showErrorMessage(data: cstring, length: int) {.gcsafe, raises: [].} =
var toWrite = true var toWrite = true
if errorMessageWriter != nil: if errorMessageWriter != nil:
@ -51,6 +57,9 @@ proc showErrorMessage(data: cstring, length: int) {.gcsafe, raises: [].} =
else: else:
writeToStdErr(data, length) writeToStdErr(data, length)
proc showErrorMessage2(data: string) {.inline.} =
showErrorMessage(data.cstring, data.len)
proc chckIndx(i, a, b: int): int {.inline, compilerproc, benign.} proc chckIndx(i, a, b: int): int {.inline, compilerproc, benign.}
proc chckRange(i, a, b: int): int {.inline, compilerproc, benign.} proc chckRange(i, a, b: int): int {.inline, compilerproc, benign.}
proc chckRangeF(x, a, b: float): float {.inline, compilerproc, benign.} proc chckRangeF(x, a, b: float): float {.inline, compilerproc, benign.}
@ -123,11 +132,11 @@ proc popSafePoint {.compilerRtl, inl.} =
proc pushCurrentException(e: sink(ref Exception)) {.compilerRtl, inl.} = proc pushCurrentException(e: sink(ref Exception)) {.compilerRtl, inl.} =
e.up = currException e.up = currException
currException = e currException = e
#showErrorMessage "A" #showErrorMessage2 "A"
proc popCurrentException {.compilerRtl, inl.} = proc popCurrentException {.compilerRtl, inl.} =
currException = currException.up currException = currException.up
#showErrorMessage "B" #showErrorMessage2 "B"
proc popCurrentExceptionEx(id: uint) {.compilerRtl.} = proc popCurrentExceptionEx(id: uint) {.compilerRtl.} =
discard "only for bootstrapping compatbility" discard "only for bootstrapping compatbility"
@ -305,7 +314,7 @@ when hasSomeStackTrace:
auxWriteStackTraceWithOverride(s) auxWriteStackTraceWithOverride(s)
elif NimStackTrace: elif NimStackTrace:
if framePtr == nil: if framePtr == nil:
add(s, "No stack traceback available\n") add(s, noStacktraceAvailable)
else: else:
add(s, "Traceback (most recent call last)\n") add(s, "Traceback (most recent call last)\n")
auxWriteStackTrace(framePtr, s) auxWriteStackTrace(framePtr, s)
@ -313,7 +322,7 @@ when hasSomeStackTrace:
add(s, "Traceback from system (most recent call last)\n") add(s, "Traceback from system (most recent call last)\n")
auxWriteStackTraceWithBacktrace(s) auxWriteStackTraceWithBacktrace(s)
else: else:
add(s, "No stack traceback available\n") add(s, noStacktraceAvailable)
proc rawWriteStackTrace(s: var seq[StackTraceEntry]) = proc rawWriteStackTrace(s: var seq[StackTraceEntry]) =
when defined(nimStackTraceOverride): when defined(nimStackTraceOverride):
@ -363,7 +372,7 @@ proc reportUnhandledErrorAux(e: ref Exception) {.nodestroy.} =
if onUnhandledException != nil: if onUnhandledException != nil:
onUnhandledException(buf) onUnhandledException(buf)
else: else:
showErrorMessage(buf, buf.len) showErrorMessage2(buf)
`=destroy`(buf) `=destroy`(buf)
else: else:
# ugly, but avoids heap allocations :-) # ugly, but avoids heap allocations :-)
@ -504,16 +513,16 @@ proc writeStackTrace() =
when hasSomeStackTrace: when hasSomeStackTrace:
var s = "" var s = ""
rawWriteStackTrace(s) rawWriteStackTrace(s)
cast[proc (s: cstring, length: int) {.noSideEffect, tags: [], nimcall, raises: [].}](showErrorMessage)(s, s.len)
else: else:
cast[proc (s: cstring, length: int) {.noSideEffect, tags: [], nimcall, raises: [].}](showErrorMessage)("No stack traceback available\n", 32) let s = noStacktraceAvailable
cast[proc (s: string) {.noSideEffect, tags: [], nimcall, raises: [].}](showErrorMessage2)(s)
proc getStackTrace(): string = proc getStackTrace(): string =
when hasSomeStackTrace: when hasSomeStackTrace:
result = "" result = ""
rawWriteStackTrace(result) rawWriteStackTrace(result)
else: else:
result = "No stack traceback available\n" result = noStacktraceAvailable
proc getStackTrace(e: ref Exception): string = proc getStackTrace(e: ref Exception): string =
if not isNil(e): if not isNil(e):
@ -543,7 +552,7 @@ proc callDepthLimitReached() {.noinline.} =
$nimCallDepthLimit & " function calls). You can change it with " & $nimCallDepthLimit & " function calls). You can change it with " &
"-d:nimCallDepthLimit=<int> but really try to avoid deep " & "-d:nimCallDepthLimit=<int> but really try to avoid deep " &
"recursions instead.\n" "recursions instead.\n"
showErrorMessage(msg, msg.len) showErrorMessage2(msg)
quit(1) quit(1)
proc nimFrame(s: PFrame) {.compilerRtl, inl, raises: [].} = proc nimFrame(s: PFrame) {.compilerRtl, inl, raises: [].} =
@ -627,13 +636,16 @@ when not defined(noSignalHandler) and not defined(useNimRtl):
var buf = newStringOfCap(2000) var buf = newStringOfCap(2000)
rawWriteStackTrace(buf) rawWriteStackTrace(buf)
processSignal(sign, buf.add) # nice hu? currying a la Nim :-) processSignal(sign, buf.add) # nice hu? currying a la Nim :-)
showErrorMessage(buf, buf.len) showErrorMessage2(buf)
when not usesDestructors: GC_enable() when not usesDestructors: GC_enable()
else: else:
var msg: cstring var msg: cstring
template asgn(y) = template asgn(y) =
msg = y msg = y
processSignal(sign, asgn) processSignal(sign, asgn)
# xxx use string for msg instead of cstring, and here use showErrorMessage2(msg)
# unless there's a good reason to use cstring in signal handler to avoid
# using gc?
showErrorMessage(msg, msg.len) showErrorMessage(msg, msg.len)
quit(1) # always quit when SIGABRT quit(1) # always quit when SIGABRT

View file

@ -1,12 +1,38 @@
discard """ const msg = "This char is `" & '\0' & "` and works fine!"
exitcode: 1
targets: "c"
matrix: "-d:debug; -d:release"
outputsub: ''' and works fine! [Exception]'''
"""
# bug #13115 when defined nim_t13115:
# xxx bug: doesn't yet work for cpp # bug #13115
template fn =
raise newException(Exception, msg)
when defined nim_t13115_static:
static: fn()
fn()
else:
import std/[osproc,strformat,os,strutils]
proc main =
const nim = getCurrentCompilerExe()
const file = currentSourcePath
for b in "c js cpp".split:
when defined(openbsd):
if b == "js":
# xxx bug: pending #13115
# remove special case once nodejs updated >= 12.16.2
# refs https://github.com/nim-lang/Nim/pull/16167#issuecomment-738270751
continue
var msg = "This char is `" & '\0' & "` and works fine!" # save CI time by avoiding mostly redundant combinations as far as this bug is concerned
raise newException(Exception, msg) var opts = case b
of "c": @["", "-d:nim_t13115_static", "-d:danger", "-d:debug"]
of "js": @["", "-d:nim_t13115_static"]
else: @[""]
for opt in opts:
let cmd = fmt"{nim} r -b:{b} -d:nim_t13115 {opt} --hints:off {file}"
let (outp, exitCode) = execCmdEx(cmd)
when defined windows:
# `\0` not preserved on windows
doAssert "` and works fine!" in outp, cmd & "\n" & msg
else:
doAssert msg in outp, cmd & "\n" & msg
doAssert exitCode == 1
main()