Skip to content

Commit 60eec01

Browse files
committed
ChildProcess: account for a system error when launching a process
When a non-existing command is attempted to run, both status and signal will be null, which leads to ChildProcess module crashing. Obviously, this is incorrect behavior. The problem is more general than that though: any system error that would result in failing to run a process would result in the module crash. Fix that by checking for such case. Fixes: #65
1 parent 49f2765 commit 60eec01

File tree

4 files changed

+21
-8
lines changed

4 files changed

+21
-8
lines changed

CHANGELOG.md

+3-1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ New features:
1010

1111
Bugfixes:
1212

13+
- Account for child creation to possibly fail with system error (#66 by @Hi-Angel)
14+
1315
Other improvements:
1416

1517
## [v11.1.0](https://github.com/purescript-node/purescript-node-child-process/releases/tag/v11.1.0) - 2023-11-14
@@ -76,7 +78,7 @@ Breaking changes:
7678
- Moved from `Node.ChildProces` to `Node.ChildProces.Types`
7779
- Changed the `BySignal`'s constructor's arg type from `Signal` to `String`
7880
- Breaking changes made to the `Handle` type (#46 by @JordanMartinez)
79-
81+
8082
- Moved from `Node.ChildProces` to `Node.ChildProces.Types`
8183
- Converted `defaultOptions { override = Just 1}` pattern to `(_ { override = Just 1})` (#46 by @JordanMartinez)
8284

src/Node/ChildProcess.purs

+12-4
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
-- | defined in this library that doesn't exist in the Node docs.
2222
-- | It exists to allow the end-user to append additional values to the `safeStdio` value
2323
-- | used here. For example,
24-
-- |
24+
-- |
2525
-- | ```
2626
-- | spawn' file args (_ { appendStdio = Just [ fileDescriptor8, pipe, pipe ]})
2727
-- | ```
@@ -86,7 +86,7 @@ module Node.ChildProcess
8686

8787
import Prelude
8888

89-
import Data.Maybe (Maybe(..), fromMaybe)
89+
import Data.Maybe (Maybe(..), fromMaybe, isJust)
9090
import Data.Nullable (Nullable, toMaybe, toNullable)
9191
import Data.Posix (Pid, Gid, Uid)
9292
import Data.Posix.Signal (Signal)
@@ -237,7 +237,11 @@ spawnSync command args = (UnsafeCP.spawnSync command args) <#> \r ->
237237
, exitStatus: case toMaybe r.status, toMaybe r.signal of
238238
Just c, _ -> Normally c
239239
_, Just s -> BySignal s
240-
_, _ -> unsafeCrashWith $ "Impossible: `spawnSync` child process neither exited nor was killed."
240+
_, _ ->
241+
if isJust $ toMaybe r.error then
242+
BySysError
243+
else
244+
unsafeCrashWith $ "Impossible: `spawnSync` child process neither exited nor was killed."
241245
, error: toMaybe r.error
242246
}
243247

@@ -282,7 +286,11 @@ spawnSync' command args buildOpts = (UnsafeCP.spawnSync' command args opts) <#>
282286
, exitStatus: case toMaybe r.status, toMaybe r.signal of
283287
Just c, _ -> Normally c
284288
_, Just s -> BySignal s
285-
_, _ -> unsafeCrashWith $ "Impossible: `spawnSync` child process neither exited nor was killed."
289+
_, _ ->
290+
if isJust $ toMaybe r.error then
291+
BySysError
292+
else
293+
unsafeCrashWith $ "Impossible: `spawnSync` child process neither exited nor was killed."
286294
, error: toMaybe r.error
287295
}
288296
where

src/Node/ChildProcess/Types.purs

+5-3
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ foreign import data StdIO :: Type
5252
-- | Note: when used with `stdin`, piping the parent stdin to this stream
5353
-- | will not cause the child process to terminate when that parent stdin stream
5454
-- | ends via `Ctrl+D` user input. Rather, the child process will hang
55-
-- | until the parent process calls `Stream.end` on the child process'
55+
-- | until the parent process calls `Stream.end` on the child process'
5656
-- | `stdin` stream. Since it's impossible to know when the user
5757
-- | inputs `Ctrl+D`, `inherit` should be used instead.
5858
pipe :: StdIO
@@ -140,12 +140,14 @@ customShell = unsafeCoerce
140140
-- | what options were used.
141141
foreign import data StringOrBuffer :: Type
142142

143-
-- | Specifies how a child process exited; normally (with an exit code), or
144-
-- | due to a signal.
143+
-- | Specifies how a child process exited; normally (with an exit code), due to
144+
-- | a signal or if it failed to even launch (e.g. if a command doesn't exist).
145145
data Exit
146146
= Normally Int
147147
| BySignal KillSignal
148+
| BySysError
148149

149150
instance showExit :: Show Exit where
150151
show (Normally x) = "Normally " <> show x
151152
show (BySignal sig) = "BySignal " <> (either show show $ fromKillSignal sig)
153+
show BySysError = "BySysError"

test/Main.purs

+1
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ spawnLs = do
7272
Normally 0 -> log $ "ls exited with 0"
7373
Normally i -> liftEffect $ throw $ "ls had non-zero exit: " <> show i
7474
BySignal sig -> liftEffect $ throw $ "ls exited with sig: " <> show sig
75+
BySysError -> liftEffect $ throw "ls exited with system error"
7576

7677
nonExistentExecutable :: Aff Unit
7778
nonExistentExecutable = do

0 commit comments

Comments
 (0)