Skip to content

Commit

Permalink
Make 'echo' raise IOErrors when appropriate (nim-lang#16367)
Browse files Browse the repository at this point in the history
* Make 'echo' raise IOError when fwrite/fflush fail

* Fix fwrite return value comparison

* Add test for echo raising error and don't fail to release locks in echo

* Fix exitcode expectation

* Make 'echo' raise IOError on Windows if it fails

* Add nimLegacyEchoNoRaise for prior no-IOError echo behavior

* Use checkErrMaybe template
  • Loading branch information
iffy authored and mildred committed Jan 11, 2021
1 parent 04e4657 commit 837bbc9
Show file tree
Hide file tree
Showing 3 changed files with 30 additions and 8 deletions.
3 changes: 3 additions & 0 deletions changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,9 @@

- Added `math.isNaN`.

- `echo` and `debugEcho` will now raise `IOError` if writing to stdout fails. Previous behavior
silently ignored errors. See #16366. Use `-d:nimLegacyEchoNoRaise` for previous behavior.

## Language changes

- `nimscript` now handles `except Exception as e`.
Expand Down
24 changes: 16 additions & 8 deletions lib/system/io.nim
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,9 @@ when defined(windows):
# But we cannot call printf directly as the string might contain \0.
# So we have to loop over all the sections separated by potential \0s.
var i = c_fprintf(f, "%s", s)
if i < 0:
if doRaise: raiseEIO("cannot write string to file")
return
while i < s.len:
if s[i] == '\0':
let w = c_fputc('\0', f)
Expand Down Expand Up @@ -780,6 +783,13 @@ when declared(stdout):
not defined(nintendoswitch) and not defined(freertos) and
hostOS != "any"

const echoDoRaise = not defined(nimLegacyEchoNoRaise) # see PR #16366

template checkErrMaybe(succeeded: bool): untyped =
if not succeeded:
when echoDoRaise:
checkErr(stdout)

proc echoBinSafe(args: openArray[string]) {.compilerproc.} =
when defined(androidNDK):
var s = ""
Expand All @@ -792,20 +802,18 @@ when declared(stdout):
proc flockfile(f: File) {.importc, nodecl.}
proc funlockfile(f: File) {.importc, nodecl.}
flockfile(stdout)
defer: funlockfile(stdout)
when defined(windows) and compileOption("threads"):
acquireSys echoLock
defer: releaseSys echoLock
for s in args:
when defined(windows):
writeWindows(stdout, s)
writeWindows(stdout, s, doRaise = echoDoRaise)
else:
discard c_fwrite(s.cstring, cast[csize_t](s.len), 1, stdout)
checkErrMaybe(c_fwrite(s.cstring, cast[csize_t](s.len), 1, stdout) == s.len)
const linefeed = "\n"
discard c_fwrite(linefeed.cstring, linefeed.len, 1, stdout)
discard c_fflush(stdout)
when stdOutLock:
funlockfile(stdout)
when defined(windows) and compileOption("threads"):
releaseSys echoLock
checkErrMaybe(c_fwrite(linefeed.cstring, linefeed.len, 1, stdout) == linefeed.len)
checkErrMaybe(c_fflush(stdout) == 0)


when defined(windows) and not defined(nimscript) and not defined(js):
Expand Down
11 changes: 11 additions & 0 deletions tests/exception/t16366.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
discard """
action: run
exitcode: 0
targets: "c cpp"
disabled: openbsd
"""

echo "foo1"
close stdout
doAssertRaises(IOError):
echo "foo"

0 comments on commit 837bbc9

Please sign in to comment.