summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorMichał Zieliński <michal@zielinscy.org.pl>2018-04-16 20:02:26 +0200
committerAndreas Rumpf <rumpf_a@web.de>2018-04-16 20:02:26 +0200
commitb2060acbc49ccface03a2350bf1c2e9ad456a75d (patch)
tree94e009771123efd276fc391899d5eda0bcb769ce
parent412cd61dabe160708c502e37a48b9c3c7c2c6017 (diff)
downloadNim-b2060acbc49ccface03a2350bf1c2e9ad456a75d.tar.gz
osproc: fix double close on POSIX (#5724)
Calling close() in some cases issued two close() syscalls to one FD, which is incorrect in multithreaded programs.
-rw-r--r--lib/pure/osproc.nim20
-rw-r--r--tests/osproc/tclose.nim24
2 files changed, 38 insertions, 6 deletions
diff --git a/lib/pure/osproc.nim b/lib/pure/osproc.nim
index 555626514..a51b1f5ab 100644
--- a/lib/pure/osproc.nim
+++ b/lib/pure/osproc.nim
@@ -1001,13 +1001,21 @@ elif not defined(useNimRtl):
   {.pop}
 
   proc close(p: Process) =
-    if p.inStream != nil: close(p.inStream)
-    if p.outStream != nil: close(p.outStream)
-    if p.errStream != nil: close(p.errStream)
     if poParentStreams notin p.options:
-      discard close(p.inHandle)
-      discard close(p.outHandle)
-      discard close(p.errHandle)
+      if p.inStream != nil:
+        close(p.inStream)
+      else:
+        discard close(p.inHandle)
+
+      if p.outStream != nil:
+        close(p.outStream)
+      else:
+        discard close(p.outHandle)
+
+      if p.errStream != nil:
+        close(p.errStream)
+      else:
+        discard close(p.errHandle)
 
   proc suspend(p: Process) =
     if kill(p.id, SIGSTOP) != 0'i32: raiseOsError(osLastError())
diff --git a/tests/osproc/tclose.nim b/tests/osproc/tclose.nim
new file mode 100644
index 000000000..d466b466a
--- /dev/null
+++ b/tests/osproc/tclose.nim
@@ -0,0 +1,24 @@
+discard """
+  exitcode: 0
+"""
+
+when defined(linux):
+  import osproc, os
+
+  proc countFds(): int =
+    result = 0
+    for i in walkDir("/proc/self/fd"):
+      result += 1
+
+  let initCount = countFds()
+
+  let p = osproc.startProcess("echo", options={poUsePath})
+  assert countFds() == initCount + 3
+  p.close
+  assert countFds() == initCount
+
+  let p1 = osproc.startProcess("echo", options={poUsePath})
+  discard p1.inputStream
+  assert countFds() == initCount + 3
+  p.close
+  assert countFds() == initCount