Skip to content

Commit 03d4f94

Browse files
committed
TSCBasic: properly track abnormal exits on Windows
The process handling did not properly account for abnormal process termination. Unlike Unix platforms, Windows does not have a concept of signals. However, a process may be terminated abnormally by means of an exception. The exception code is then transliterated into the exit code for the process. In most circumstances, the exit code for the process in such a case is either a `NTSTATUS` or `HRESULT`. Accordingly, the way to detect the exception is to check the severity code of the exception. The `HRESULT` and `NTSTATUS` codes are similarly structured: ~~~ 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |S|R|C|N|X|F A C I L I T Y |C O D E | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ S: Severity; If set, indicates a failure result. If clear, indicates a success result. R: Reserved; If N is clear, this bit MUST be set to 0. C: Customer; If set, indicates that this a customer defined error code. N: If set, indicates that the error code is a NTSTATUS value. X: Reserved; MBZ Facility: An indicator of the source of the error. Code: The remainder of the error code. ~~~ We would previously only check for the top nibble being 0xC or 0xE. However, a 0x8 value is also permissible and indicates a failure. Plumb this through as an abnormal exit with the specified exception code.
1 parent 32846eb commit 03d4f94

File tree

1 file changed

+15
-3
lines changed

1 file changed

+15
-3
lines changed

Sources/TSCBasic/Process.swift

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,10 @@ public struct ProcessResult: CustomStringConvertible {
3434
public enum ExitStatus: Equatable {
3535
/// The process was terminated normally with a exit code.
3636
case terminated(code: Int32)
37-
#if !os(Windows)
37+
#if os(Windows)
38+
/// The process was terminated abnormally.
39+
case abnormal(exception: UInt32)
40+
#else
3841
/// The process was terminated due to a signal.
3942
case signalled(signal: Int32)
4043
#endif
@@ -64,12 +67,17 @@ public struct ProcessResult: CustomStringConvertible {
6467
arguments: [String],
6568
environment: [String: String],
6669
exitStatusCode: Int32,
70+
normal: Bool,
6771
output: Result<[UInt8], Swift.Error>,
6872
stderrOutput: Result<[UInt8], Swift.Error>
6973
) {
7074
let exitStatus: ExitStatus
7175
#if os(Windows)
72-
exitStatus = .terminated(code: exitStatusCode)
76+
if normal {
77+
exitStatus = .terminated(code: exitStatusCode)
78+
} else {
79+
exitStatus = .abnormal(exception: exitStatusCode)
80+
}
7381
#else
7482
if WIFSIGNALED(exitStatusCode) {
7583
exitStatus = .signalled(signal: WTERMSIG(exitStatusCode))
@@ -742,6 +750,7 @@ public final class Process {
742750
arguments: arguments,
743751
environment: environment,
744752
exitStatusCode: exitStatusCode,
753+
normal: p.terminationReason == .exit,
745754
output: stdoutResult,
746755
stderrOutput: stderrResult
747756
)
@@ -970,7 +979,10 @@ extension ProcessResult.Error: CustomStringConvertible {
970979
switch result.exitStatus {
971980
case .terminated(let code):
972981
stream <<< "terminated(\(code)): "
973-
#if !os(Windows)
982+
#if os(Windows)
983+
case .abnormal(let exception):
984+
stream <<< "abnormal(\(exception)): "
985+
#else
974986
case .signalled(let signal):
975987
stream <<< "signalled(\(signal)): "
976988
#endif

0 commit comments

Comments
 (0)