Skip to content

Commit 070bbe5

Browse files
committed
fix #17749 SIGPIPE
1 parent 8e474fb commit 070bbe5

File tree

4 files changed

+46
-17
lines changed

4 files changed

+46
-17
lines changed

changelog.md

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,18 @@
3737
- In `std/os`, `getHomeDir`, `expandTilde`, `getTempDir`, `getConfigDir` now do not include trailing `DirSep`,
3838
unless `-d:nimLegacyHomeDir` is specified (for a transition period).
3939

40+
- On POSIX systems, the default signal handlers used for Nim programs (it's
41+
used for printing the stacktrace on fatal signals) will now re-raise the
42+
signal for the OS default handlers to handle.
43+
44+
This lets the OS perform its default actions, which might include core
45+
dumping (on select signals) and notifying the parent process about the cause
46+
of termination.
47+
48+
- On POSIX systems, we now ignore `SIGPIPE` signals, use `-d:nimLegacySigpipeHandler`
49+
for previous behavior.
50+
51+
4052
## Standard library additions and changes
4153
- Added support for parenthesized expressions in `strformat`
4254

@@ -217,14 +229,6 @@
217229
`ValueError` when the real command line is not available. `parseopt` was
218230
previously excluded from `prelude` for JS, as it could not be imported.
219231

220-
- On POSIX systems, the default signal handlers used for Nim programs (it's
221-
used for printing the stacktrace on fatal signals) will now re-raise the
222-
signal for the OS default handlers to handle.
223-
224-
This lets the OS perform its default actions, which might include core
225-
dumping (on select signals) and notifying the parent process about the cause
226-
of termination.
227-
228232
- Added `system.prepareStrMutation` for better support of low
229233
level `moveMem`, `copyMem` operations for Orc's copy-on-write string
230234
implementation.

lib/system/excpt.nim

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -602,6 +602,9 @@ when defined(cpp) and appType != "lib" and not gotoBasedExceptions and
602602
quit 1
603603

604604
when not defined(noSignalHandler) and not defined(useNimRtl):
605+
type Sighandler = proc (a: cint) {.noconv, benign.}
606+
# xxx factor with ansi_c.CSighandlerT, posix.Sighandler
607+
605608
proc signalHandler(sign: cint) {.exportc: "signalHandler", noconv.} =
606609
template processSignal(s, action: untyped) {.dirty.} =
607610
if s == SIGINT: action("SIGINT: Interrupted by Ctrl-C.\n")
@@ -652,7 +655,11 @@ when not defined(noSignalHandler) and not defined(useNimRtl):
652655
else:
653656
quit(1)
654657

658+
var SIG_IGN {.importc: "SIG_IGN", header: "<signal.h>".}: Sighandler
659+
655660
proc registerSignalHandler() =
661+
# xxx `signal` is deprecated and has many caveats, we should use `sigaction` instead, e.g.
662+
# https://stackoverflow.com/questions/231912/what-is-the-difference-between-sigaction-and-signal
656663
c_signal(SIGINT, signalHandler)
657664
c_signal(SIGSEGV, signalHandler)
658665
c_signal(SIGABRT, signalHandler)
@@ -661,14 +668,16 @@ when not defined(noSignalHandler) and not defined(useNimRtl):
661668
when declared(SIGBUS):
662669
c_signal(SIGBUS, signalHandler)
663670
when declared(SIGPIPE):
664-
c_signal(SIGPIPE, signalHandler)
671+
when defined(nimLegacySigpipeHandler):
672+
c_signal(SIGPIPE, signalHandler)
673+
else:
674+
c_signal(SIGPIPE, SIG_IGN)
665675

666676
registerSignalHandler() # call it in initialization section
667677

668678
proc setControlCHook(hook: proc () {.noconv.}) =
669679
# ugly cast, but should work on all architectures:
670-
type SignalHandler = proc (sign: cint) {.noconv, benign.}
671-
c_signal(SIGINT, cast[SignalHandler](hook))
680+
c_signal(SIGINT, cast[Sighandler](hook))
672681

673682
when not defined(noSignalHandler) and not defined(useNimRtl):
674683
proc unsetControlCHook() =

tests/stdlib/tosproc.nim

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -206,8 +206,8 @@ else: # main driver
206206
var line = newStringOfCap(120)
207207
while true:
208208
if outp.readLine(line):
209-
result[0].string.add(line.string)
210-
result[0].string.add("\n")
209+
result[0].add(line)
210+
result[0].add("\n")
211211
else:
212212
result[1] = peekExitCode(p)
213213
if result[1] != -1: break
@@ -279,3 +279,16 @@ else: # main driver
279279
when defined(posix):
280280
doAssert execCmdEx("echo $FO", env = newStringTable({"FO": "B"})) == ("B\n", 0)
281281
doAssert execCmdEx("echo $PWD", workingDir = "/") == ("/\n", 0)
282+
283+
block: # bug #17749
284+
let output = compileNimProg("-d:case_testfile4", "D20210417T011153")
285+
var p = startProcess(output, dir)
286+
let inp = p.inputStream
287+
var count = 0
288+
doAssertRaises(IOError):
289+
for i in 0..<100000:
290+
count.inc
291+
inp.writeLine "ok" # was giving SIGPIPE and crashing
292+
doAssert count >= 100
293+
doAssert waitForExit(p) == QuitFailure
294+
close(p) # xxx isn't that missing in other places?

tests/system/tsigexitcode.nim

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,13 @@ proc main() =
1111
discard posix.raise(signal)
1212
else:
1313
# synchronize this list with lib/system/except.nim:registerSignalHandler()
14-
let fatalSigs = [SIGINT, SIGSEGV, SIGABRT, SIGFPE, SIGILL, SIGBUS,
15-
SIGPIPE]
16-
for s in fatalSigs:
14+
let sigs = [SIGINT, SIGSEGV, SIGABRT, SIGFPE, SIGILL, SIGBUS, SIGPIPE]
15+
for s in sigs:
1716
let (_, exitCode) = execCmdEx(quoteShellCommand [getAppFilename(), $s])
18-
doAssert exitCode == 128 + s, "mismatched exit code for signal " & $s
17+
if s == SIGPIPE:
18+
# SIGPIPE should be ignored
19+
doAssert exitCode == 0, $(exitCode, s)
20+
else:
21+
doAssert exitCode == 128+s, $(exitCode, s)
1922

2023
main()

0 commit comments

Comments
 (0)