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

fixes #20694; range check the parameter of the proc quit #20718

Closed
wants to merge 16 commits into from
2 changes: 1 addition & 1 deletion lib/genode/alloc.nim
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ proc osDeallocPages(p: pointer; size: int) =
if m.attachment == p:
if m.size != size:
echo "cannot partially detach dataspace"
quit -1
rawQuit -1
runtimeEnv.detachAddress m.attachment
runtimeEnv.freeDataspace m.ds
m[] = Map()
Expand Down
4 changes: 1 addition & 3 deletions lib/std/assertions.nim
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,6 @@

## This module implements assertion handling.

import system/fatal

import std/private/miscdollars
# ---------------------------------------------------------------------------
# helpers
Expand All @@ -30,7 +28,7 @@ when not defined(nimHasSinkInference):

proc raiseAssert*(msg: string) {.noinline, noreturn, nosinks.} =
## Raises an `AssertionDefect` with `msg`.
sysFatal(AssertionDefect, msg)
raise newException(AssertionDefect, msg)
ringabout marked this conversation as resolved.
Show resolved Hide resolved

proc failedAssertImpl*(msg: string) {.raises: [], tags: [].} =
## Raises an `AssertionDefect` with `msg`, but this is hidden
Expand Down
169 changes: 90 additions & 79 deletions lib/system.nim
Original file line number Diff line number Diff line change
Expand Up @@ -1086,64 +1086,7 @@ proc align(address, alignment: int): int =
else:
result = (address + (alignment - 1)) and not (alignment - 1)

when defined(nimNoQuit):
proc quit*(errorcode: int = QuitSuccess) = discard "ignoring quit"
ringabout marked this conversation as resolved.
Show resolved Hide resolved
## Stops the program immediately with an exit code.
##
## Before stopping the program the "exit procedures" are called in the
## opposite order they were added with `addExitProc <exitprocs.html#addExitProc,proc)>`_.
##
## The proc `quit(QuitSuccess)` is called implicitly when your nim
## program finishes without incident for platforms where this is the
## expected behavior. A raised unhandled exception is
## equivalent to calling `quit(QuitFailure)`.
##
## Note that this is a *runtime* call and using `quit` inside a macro won't
## have any compile time effect. If you need to stop the compiler inside a
## macro, use the `error <manual.html#pragmas-error-pragma>`_ or `fatal
## <manual.html#pragmas-fatal-pragma>`_ pragmas.
##
## .. danger:: In almost all cases, in particular in library code, prefer
## alternatives, e.g. `doAssert false` or raise a `Defect`.
## `quit` bypasses regular control flow in particular `defer`,
## `try`, `catch`, `finally` and `destructors`, and exceptions that may have been
## raised by an `addExitProc` proc, as well as cleanup code in other threads.
## It does *not* call the garbage collector to free all the memory,
## unless an `addExitProc` proc calls `GC_fullCollect <#GC_fullCollect>`_.

elif defined(nimdoc):
proc quit*(errorcode: int = QuitSuccess) {.magic: "Exit", noreturn.}

elif defined(genode):
import genode/env

var systemEnv {.exportc: runtimeEnvSym.}: GenodeEnvPtr

type GenodeEnv* = GenodeEnvPtr
## Opaque type representing Genode environment.

proc quit*(env: GenodeEnv; errorcode: int) {.magic: "Exit", noreturn,
importcpp: "#->parent().exit(@); Genode::sleep_forever()", header: "<base/sleep.h>".}

proc quit*(errorcode: int = QuitSuccess) =
systemEnv.quit(errorcode)

elif defined(js) and defined(nodejs) and not defined(nimscript):
proc quit*(errorcode: int = QuitSuccess) {.magic: "Exit",
importc: "process.exit", noreturn.}

else:
proc quit*(errorcode: int = QuitSuccess) {.
magic: "Exit", importc: "exit", header: "<stdlib.h>", noreturn.}


template sysAssert(cond: bool, msg: string) =
when defined(useSysAssert):
if not cond:
cstderr.rawWrite "[SYSASSERT] "
cstderr.rawWrite msg
cstderr.rawWrite "\n"
quit 1

const hasAlloc = (hostOS != "standalone" or not defined(nogc)) and not defined(nimscript)

Expand Down Expand Up @@ -1608,6 +1551,36 @@ when notJSnotNims:

{.push stackTrace: off.}

when not defined(nimscript):
proc writeStackTrace*() {.tags: [], gcsafe, raises: [].}
## Writes the current stack trace to `stderr`. This is only works
## for debug builds. Since it's usually used for debugging, this
## is proclaimed to have no IO effect!

{.pop.}

when defined(nimHasExceptionsQuery):
const gotoBasedExceptions = compileOption("exceptions", "goto")
else:
const gotoBasedExceptions = false

when defined(genode):
import genode/env
type GenodeEnv* = GenodeEnvPtr
## Opaque type representing Genode environment.

include system/fatal

template sysAssert(cond: bool, msg: string) =
when defined(useSysAssert):
if not cond:
cstderr.rawWrite "[SYSASSERT] "
cstderr.rawWrite msg
cstderr.rawWrite "\n"
rawQuit 1

{.push stackTrace: off.}

when not defined(js) and hasThreadSupport and hostOS != "standalone":
import std/private/syslocks
include "system/threadlocalstorage"
Expand All @@ -1631,19 +1604,6 @@ when notJSnotNims and defined(nimSeqsV2):

{.pop.}

when not defined(nimscript):
proc writeStackTrace*() {.tags: [], gcsafe, raises: [].}
## Writes the current stack trace to `stderr`. This is only works
## for debug builds. Since it's usually used for debugging, this
## is proclaimed to have no IO effect!


when defined(nimHasExceptionsQuery):
const gotoBasedExceptions = compileOption("exceptions", "goto")
else:
const gotoBasedExceptions = false

import system/fatal

when not defined(nimscript):
{.push stackTrace: off, profiler: off.}
Expand All @@ -1656,6 +1616,12 @@ when not defined(nimscript):
when defined(nimV2):
include system/arc

template newException*(exceptn: typedesc, message: string;
parentException: ref Exception = nil): untyped =
## Creates an exception object of type `exceptn` and sets its `msg` field
## to `message`. Returns the new exception object.
(ref exceptn)(msg: message, parent: parentException)

when not defined(nimPreviewSlimSystem):
{.deprecated: "assertions is about to move out of system; use `-d:nimPreviewSlimSystem` and import `std/assertions`".}
import std/assertions
Expand Down Expand Up @@ -1863,11 +1829,6 @@ proc debugEcho*(x: varargs[typed, `$`]) {.magic: "Echo", noSideEffect,
## for debugging routines marked as `noSideEffect
## <manual.html#pragmas-nosideeffect-pragma>`_.

template newException*(exceptn: typedesc, message: string;
parentException: ref Exception = nil): untyped =
## Creates an exception object of type `exceptn` and sets its `msg` field
## to `message`. Returns the new exception object.
(ref exceptn)(msg: message, parent: parentException)

when hostOS == "standalone" and defined(nogc):
proc nimToCStringConv(s: NimString): cstring {.compilerproc, inline.} =
Expand Down Expand Up @@ -2285,16 +2246,66 @@ when defined(js):
include "system/jssys"
include "system/reprjs"

proc quit*(errormsg: string, errorcode = QuitFailure) {.noreturn.} =
## A shorthand for `echo(errormsg); quit(errorcode)`.
template printErrorMessage(errormsg: string) =
when defined(nimscript) or defined(js) or (hostOS == "standalone"):
echo errormsg
else:
when nimvm:
echo errormsg
else:
cstderr.rawWrite(errormsg)
cstderr.rawWrite(errormsg.cstring)
cstderr.rawWrite("\n")

when defined(nimNoQuit):
proc quit*(errorcode: int = QuitSuccess) = discard "ignoring quit"
## Stops the program immediately with an exit code.
##
## Before stopping the program the "exit procedures" are called in the
## opposite order they were added with `addExitProc <exitprocs.html#addExitProc,proc)>`_.
##
## The proc `quit(QuitSuccess)` is called implicitly when your nim
## program finishes without incident for platforms where this is the
## expected behavior. A raised unhandled exception is
## equivalent to calling `quit(QuitFailure)`.
##
## Note that this is a *runtime* call and using `quit` inside a macro won't
## have any compile time effect. If you need to stop the compiler inside a
## macro, use the `error <manual.html#pragmas-error-pragma>`_ or `fatal
## <manual.html#pragmas-fatal-pragma>`_ pragmas.
##
## .. danger:: In almost all cases, in particular in library code, prefer
## alternatives, e.g. `doAssert false` or raise a `Defect`.
## `quit` bypasses regular control flow in particular `defer`,
## `try`, `catch`, `finally` and `destructors`, and exceptions that may have been
## raised by an `addExitProc` proc, as well as cleanup code in other threads.
## It does *not* call the garbage collector to free all the memory,
## unless an `addExitProc` proc calls `GC_fullCollect <#GC_fullCollect>`_.

elif defined(nimdoc):
proc quit*(errorcode: int = QuitSuccess) {.magic: "Exit", noreturn.}

elif defined(genode):
proc quit*(errorcode: int = QuitSuccess) {.inline, noreturn.} =
rawQuit(errorcode)

elif defined(js) and defined(nodejs) and not defined(nimscript):
proc quit*(errorcode: int = QuitSuccess) {.magic: "Exit",
importc: "process.exit", noreturn.}

else:
proc quit*(errorcode: int = QuitSuccess) {.inline, noreturn.} =
when defined(posix): # posix uses low 8 bits
type ExitCodeRange = int8
else: # win32 uses low 32 bits
type ExitCodeRange = int32
let errorMsg = "forced to truncate exit code " & $errorcode & " to " & $(errorcode and high(ExitCodeRange))
if errorcode < low(ExitCodeRange) or errorcode > high(ExitCodeRange):
printErrorMessage errorMsg
ringabout marked this conversation as resolved.
Show resolved Hide resolved
rawQuit(errorcode)

proc quit*(errormsg: string, errorcode = QuitFailure) {.noreturn.} =
## A shorthand for `echo(errormsg); quit(errorcode)`.
printErrorMessage(errormsg)
quit(errorcode)

{.pop.} # checks: off
Expand Down Expand Up @@ -2667,7 +2678,7 @@ when defined(genode):
proc nim_component_construct(env: GenodeEnv) {.exportc.} =
## Procedure called during `Component::construct` by the loader.
if componentConstructHook.isNil:
env.quit(programResult)
env.rawQuit(programResult)
# No native Genode application initialization,
# exit as would POSIX.
else:
Expand Down
2 changes: 1 addition & 1 deletion lib/system/arc.nim
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ proc nimRawDispose(p: pointer, alignment: int) {.compilerRtl.} =
when defined(nimOwnedEnabled):
if head(p).rc >= rcIncrement:
cstderr.rawWrite "[FATAL] dangling references exist\n"
quit 1
rawQuit 1
when defined(nimArcDebug):
# we do NOT really free the memory here in order to reliably detect use-after-frees
if freedCells.data == nil: init(freedCells)
Expand Down
10 changes: 5 additions & 5 deletions lib/system/dyncalls.nim
Original file line number Diff line number Diff line change
Expand Up @@ -47,14 +47,14 @@ proc nimLoadLibraryError(path: string) =
copyMem(msg[msgIdx].addr, badExe.cstring, badExe.len)
discard MessageBoxA(nil, msg[0].addr, nil, 0)
cstderr.rawWrite("\n")
quit(1)
rawQuit(1)

proc procAddrError(name: cstring) {.compilerproc, nonReloadable, hcrInline.} =
# carefully written to avoid memory allocation:
cstderr.rawWrite("could not import: ")
cstderr.rawWrite(name)
cstderr.rawWrite("\n")
quit(1)
rawQuit(1)

# this code was inspired from Lua's source code:
# Lua - An Extensible Extension Language
Expand Down Expand Up @@ -180,19 +180,19 @@ elif defined(nintendoswitch) or defined(freertos) or defined(zephyr):
proc nimUnloadLibrary(lib: LibHandle) =
cstderr.rawWrite("nimUnLoadLibrary not implemented")
cstderr.rawWrite("\n")
quit(1)
rawQuit(1)

proc nimLoadLibrary(path: string): LibHandle =
cstderr.rawWrite("nimLoadLibrary not implemented")
cstderr.rawWrite("\n")
quit(1)
rawQuit(1)


proc nimGetProcAddr(lib: LibHandle, name: cstring): ProcAddr =
cstderr.rawWrite("nimGetProAddr not implemented")
cstderr.rawWrite(name)
cstderr.rawWrite("\n")
quit(1)
rawQuit(1)

else:
{.error: "no implementation for dyncalls".}
Expand Down
16 changes: 8 additions & 8 deletions lib/system/excpt.nim
Original file line number Diff line number Diff line change
Expand Up @@ -415,7 +415,7 @@ proc nimLeaveFinally() {.compilerRtl.} =
c_longjmp(excHandler.context, 1)
else:
reportUnhandledError(currException)
quit(1)
rawQuit(1)

when gotoBasedExceptions:
var nimInErrorMode {.threadvar.}: bool
Expand All @@ -430,13 +430,13 @@ when gotoBasedExceptions:
if nimInErrorMode and currException != nil:
reportUnhandledError(currException)
currException = nil
quit(1)
rawQuit(1)

proc raiseExceptionAux(e: sink(ref Exception)) {.nodestroy.} =
when defined(nimPanics):
if e of Defect:
reportUnhandledError(e)
quit(1)
rawQuit(1)

if localRaiseHook != nil:
if not localRaiseHook(e): return
Expand All @@ -458,7 +458,7 @@ proc raiseExceptionAux(e: sink(ref Exception)) {.nodestroy.} =
c_longjmp(excHandler.context, 1)
else:
reportUnhandledError(e)
quit(1)
rawQuit(1)

proc raiseExceptionEx(e: sink(ref Exception), ename, procname, filename: cstring,
line: int) {.compilerRtl, nodestroy.} =
Expand Down Expand Up @@ -501,7 +501,7 @@ proc threadTrouble() =
if currException != nil: reportUnhandledError(currException)
except:
discard
quit 1
rawQuit 1

proc writeStackTrace() =
when hasSomeStackTrace:
Expand Down Expand Up @@ -544,7 +544,7 @@ proc callDepthLimitReached() {.noinline.} =
"-d:nimCallDepthLimit=<int> but really try to avoid deep " &
"recursions instead.\n"
showErrorMessage2(msg)
quit(1)
rawQuit(1)

proc nimFrame(s: PFrame) {.compilerRtl, inl, raises: [].} =
if framePtr == nil:
Expand Down Expand Up @@ -597,7 +597,7 @@ when defined(cpp) and appType != "lib" and not gotoBasedExceptions and
else:
writeToStdErr msg & "\n"

quit 1
rawQuit 1

when not defined(noSignalHandler) and not defined(useNimRtl):
type Sighandler = proc (a: cint) {.noconv, benign.}
Expand Down Expand Up @@ -651,7 +651,7 @@ when not defined(noSignalHandler) and not defined(useNimRtl):
# also return the correct exit code to the shell.
discard c_raise(sign)
else:
quit(1)
rawQuit(1)

var SIG_IGN {.importc: "SIG_IGN", header: "<signal.h>".}: Sighandler

Expand Down
Loading