Skip to content

Commit 2f93a48

Browse files
authored
Merge branch 'devel' into pr_fix_ddc
2 parents 6018725 + 41ce86b commit 2f93a48

File tree

7 files changed

+73
-20
lines changed

7 files changed

+73
-20
lines changed

lib/pure/cgi.nim

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -289,11 +289,14 @@ Content-Type: text/html
289289
proc writeErrorMessage*(data: string) =
290290
## Tries to reset browser state and writes `data` to stdout in
291291
## <plaintext> tag.
292-
resetForStacktrace()
293-
# We use <plaintext> here, instead of escaping, so stacktrace can
294-
# be understood by human looking at source.
295-
stdout.write("<plaintext>\n")
296-
stdout.write(data)
292+
try:
293+
resetForStacktrace()
294+
# We use <plaintext> here, instead of escaping, so stacktrace can
295+
# be understood by human looking at source.
296+
stdout.write("<plaintext>\n")
297+
stdout.write(data)
298+
except IOError as exc:
299+
discard # Too bad..
297300

298301
proc setStackTraceStdout*() =
299302
## Makes Nim output stacktraces to stdout, instead of server log.

lib/pure/collections/lists.nim

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -712,6 +712,8 @@ proc remove*[T](L: var SinglyLinkedList[T], n: SinglyLinkedNode[T]): bool {.disc
712712
L.head = n.next
713713
if L.tail.next == n:
714714
L.tail.next = L.head # restore cycle
715+
if L.tail == n:
716+
L.tail = nil # reset tail if we removed the last node
715717
else:
716718
var prev {.cursor.} = L.head
717719
while prev.next != n and prev.next != nil:

lib/system.nim

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2194,18 +2194,33 @@ when not defined(js):
21942194
when declared(initGC): initGC()
21952195

21962196
when notJSnotNims:
2197-
proc setControlCHook*(hook: proc () {.noconv.})
2197+
proc setControlCHook*(hook: proc () {.noconv.}) {.raises: [], gcsafe.}
21982198
## Allows you to override the behaviour of your application when CTRL+C
21992199
## is pressed. Only one such hook is supported.
2200-
## Example:
22012200
##
2202-
## ```nim
2201+
## The handler runs inside a C signal handler and comes with similar
2202+
## limitations.
2203+
##
2204+
## Allocating memory and interacting with most system calls, including using
2205+
## `echo`, `string`, `seq`, raising or catching exceptions etc is undefined
2206+
## behavior and will likely lead to application crashes.
2207+
##
2208+
## The OS may call the ctrl-c handler from any thread, including threads
2209+
## that were not created by Nim, such as happens on Windows.
2210+
##
2211+
## ## Example:
2212+
##
2213+
## ```nim
2214+
## var stop: Atomic[bool]
22032215
## proc ctrlc() {.noconv.} =
2204-
## echo "Ctrl+C fired!"
2205-
## # do clean up stuff
2206-
## quit()
2216+
## # Using atomics types is safe!
2217+
## stop.store(true)
22072218
##
22082219
## setControlCHook(ctrlc)
2220+
##
2221+
## while not stop.load():
2222+
## echo "Still running.."
2223+
## sleep(1000)
22092224
## ```
22102225

22112226
when not defined(noSignalHandler) and not defined(useNimRtl):

lib/system/ansi_c.nim

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
# and definitions of Ansi C types in Nim syntax
1212
# All symbols are prefixed with 'c_' to avoid ambiguities
1313

14-
{.push hints:off, stack_trace: off, profiler: off.}
14+
{.push hints:off, stack_trace: off, profiler: off, raises: [].}
1515

1616
proc c_memchr*(s: pointer, c: cint, n: csize_t): pointer {.
1717
importc: "memchr", header: "<string.h>".}

lib/system/excpt.nim

Lines changed: 28 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ const noStacktraceAvailable = "No stack traceback available\n"
1717

1818
var
1919
errorMessageWriter*: (proc(msg: string) {.tags: [WriteIOEffect], benign,
20-
nimcall.})
20+
nimcall, raises: [].})
2121
## Function that will be called
2222
## instead of `stdmsg.write` when printing stacktrace.
2323
## Unstable API.
@@ -58,6 +58,7 @@ proc showErrorMessage(data: cstring, length: int) {.gcsafe, raises: [].} =
5858
writeToStdErr(data, length)
5959

6060
proc showErrorMessage2(data: string) {.inline.} =
61+
# TODO showErrorMessage will turn it back to a string when a hook is set (!)
6162
showErrorMessage(data.cstring, data.len)
6263

6364
proc chckIndx(i, a, b: int): int {.inline, compilerproc, benign.}
@@ -619,7 +620,7 @@ when not defined(noSignalHandler) and not defined(useNimRtl):
619620
type Sighandler = proc (a: cint) {.noconv, benign.}
620621
# xxx factor with ansi_c.CSighandlerT, posix.Sighandler
621622

622-
proc signalHandler(sign: cint) {.exportc: "signalHandler", noconv.} =
623+
proc signalHandler(sign: cint) {.exportc: "signalHandler", noconv, raises: [].} =
623624
template processSignal(s, action: untyped) {.dirty.} =
624625
if s == SIGINT: action("SIGINT: Interrupted by Ctrl-C.\n")
625626
elif s == SIGSEGV:
@@ -641,6 +642,22 @@ when not defined(noSignalHandler) and not defined(useNimRtl):
641642
# print stack trace and quit
642643
when defined(memtracker):
643644
logPendingOps()
645+
# On windows, it is common that the signal handler is called from a non-Nim
646+
# thread and any allocation will (likely) cause a crash. Since we're about
647+
# to quit, we can try setting up the GC - the correct course of action is to
648+
# not use the GC at all in signal handlers but that requires redesigning
649+
# the stack trace mechanism
650+
when defined(windows):
651+
when declared(initStackBottom):
652+
initStackBottom()
653+
when declared(initGC):
654+
initGC()
655+
656+
# On other platforms, if memory needs to be allocated and the signal happens
657+
# during memory allocation, we'll also (likely) see a crash and corrupt the
658+
# memory allocator - less frequently than on windows but still.
659+
# However, since we're about to go down anyway, YOLO.
660+
644661
when hasSomeStackTrace:
645662
when not usesDestructors: GC_disable()
646663
var buf = newStringOfCap(2000)
@@ -653,14 +670,17 @@ when not defined(noSignalHandler) and not defined(useNimRtl):
653670
template asgn(y) =
654671
msg = y
655672
processSignal(sign, asgn)
656-
# xxx use string for msg instead of cstring, and here use showErrorMessage2(msg)
657-
# unless there's a good reason to use cstring in signal handler to avoid
658-
# using gc?
673+
# showErrorMessage may allocate, which may cause a crash, and calls C
674+
# library functions which is undefined behavior, ie it may also crash.
675+
# Nevertheless, we sometimes manage to emit the message regardless which
676+
# pragmatically makes this attempt "useful enough".
677+
# See also https://en.cppreference.com/w/c/program/signal
659678
showErrorMessage(msg, msg.len)
660679

661680
when defined(posix):
662681
# reset the signal handler to OS default
663-
c_signal(sign, SIG_DFL)
682+
{.cast(raises: []).}: # Work around -d:laxEffects bugs
683+
discard c_signal(sign, SIG_DFL)
664684

665685
# re-raise the signal, which will arrive once this handler exit.
666686
# this lets the OS perform actions like core dumping and will
@@ -697,4 +717,5 @@ proc setControlCHook(hook: proc () {.noconv.}) =
697717
when not defined(noSignalHandler) and not defined(useNimRtl):
698718
proc unsetControlCHook() =
699719
# proc to unset a hook set by setControlCHook
700-
c_signal(SIGINT, signalHandler)
720+
{.gcsafe.}: # Work around -d:laxEffects bugs
721+
discard c_signal(SIGINT, signalHandler)

lib/system/memtracker.nim

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ type
3535
count*: int
3636
disabled: bool
3737
data*: array[400, LogEntry]
38-
TrackLogger* = proc (log: TrackLog) {.nimcall, tags: [], gcsafe.}
38+
TrackLogger* = proc (log: TrackLog) {.nimcall, tags: [], gcsafe, raises: [].}
3939

4040
var
4141
gLog*: TrackLog

tests/stdlib/tlists.nim

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -273,5 +273,17 @@ template main =
273273
list.add(n4)
274274
doAssert list.toSeq == @["sonic", "the", "hedgehog"]
275275

276+
277+
block:
278+
var list = initSinglyLinkedList[int]()
279+
280+
list.add(4)
281+
list.remove(list.head)
282+
283+
list.add(5)
284+
list.remove(list.head)
285+
286+
list.add(6)
287+
276288
static: main()
277289
main()

0 commit comments

Comments
 (0)