Here's launch-nonexistent.swift
:
import Foundation
let task = Process()
task.launchPath = "/usr/bin/nonexistantfile"
task.launch()
print("OK")
(/usr/bin/nonexistantfile
does not, in fact, exist. :)
Behavior is identical across various releases of 4.0 on each platform and the latest dev snapshot.
Running this on macOS yields: Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'launch path not accessible'
Running this on Debian testing yields: fatal error: POSIX command failed with error: 2: file Foundation/Process.swift, line 515
Running this on Ubuntu yields: OK
Inspecting task
in the REPL yields:
task: Foundation.Process = {
Foundation.NSObject = {}
launchPath = "/usr/bin/nonexistent"
arguments = nil
environment = nil
currentDirectoryPath = "/home/alex"
standardInput = nil
standardOutput = nil
standardError = nil
runLoopSourceContext = some {
version = 0
info = (_rawValue = 0x0000000000445560 -> 0x00007ffff42a7cd8 full type metadata for Foundation.Process + 16)
retain = 0x00007ffff3d94fa0 libFoundation.so`@objc Foundation.(runLoopSourceRetain in _05FBE738056ADAC488E6D2B534411459)(Swift.Optional<Swift.UnsafeRawPointer>) -> Swift.Optional<Swift.UnsafeRawPointer>
release = 0x00007ffff3d94fb0 libFoundation.so`@objc Foundation.(runLoopSourceRelease in _05FBE738056ADAC488E6D2B534411459)(Swift.Optional<Swift.UnsafeRawPointer>) -> ()
copyDescription = nil
equal = 0x00007ffff3d98390 libFoundation.so`@objc Foundation.(processIsEqual in _05FBE738056ADAC488E6D2B534411459)(Swift.Optional<Swift.UnsafeRawPointer>, Swift.Optional<Swift.UnsafeRawPointer>) -> Swift.Bool
hash = nil
schedule = nil
cancel = nil
perform = 0x00007ffff3d94fe0 libFoundation.so`@objc Foundation.(emptyRunLoopCallback in _05FBE738056ADAC488E6D2B534411459)(Swift.Optional<Swift.UnsafeMutableRawPointer>) -> ()
}
runLoopSource = 0x0000000000446910 {
Foundation.NSObject = {}
_cfinfo = 9864
}
runLoop = 0x0000000000426d80 {
Foundation.NSObject = {}
_cfRunLoop = 0x00007fffe8000e00 {
Foundation.NSObject = {}
_cfinfo = 9088
}
}
processLaunchedCondition = {
Foundation.NSObject = {}
mutex = 0x00000000004468b0
cond = 0x00000000004454b0
name = nil
}
processIdentifier = 6291
isRunning = true
terminationStatus = 0
terminationReason = exit
terminationHandler = nil
qualityOfService = default
}
Compared to a healthy task, such as /bin/ls
, there aren't many differences:
task: Foundation.Process = {
Foundation.NSObject = {}
launchPath = "/bin/ls"
arguments = nil
environment = nil
currentDirectoryPath = "/home/alex"
standardInput = nil
standardOutput = nil
standardError = nil
runLoopSourceContext = some {
version = 0
info = (_rawValue = 0x0000000000445560 -> 0x00007ffff42a7cd8 full type metadata for Foundation.Process + 16)
retain = 0x00007ffff3d94fa0 libFoundation.so`@objc Foundation.(runLoopSourceRetain in _05FBE738056ADAC488E6D2B534411459)(Swift.Optional<Swift.UnsafeRawPointer>) -> Swift.Optional<Swift.UnsafeRawPointer>
release = 0x00007ffff3d94fb0 libFoundation.so`@objc Foundation.(runLoopSourceRelease in _05FBE738056ADAC488E6D2B534411459)(Swift.Optional<Swift.UnsafeRawPointer>) -> ()
copyDescription = nil
equal = 0x00007ffff3d98390 libFoundation.so`@objc Foundation.(processIsEqual in _05FBE738056ADAC488E6D2B534411459)(Swift.Optional<Swift.UnsafeRawPointer>, Swift.Optional<Swift.UnsafeRawPointer>) -> Swift.Bool
hash = nil
schedule = nil
cancel = nil
perform = 0x00007ffff3d94fe0 libFoundation.so`@objc Foundation.(emptyRunLoopCallback in _05FBE738056ADAC488E6D2B534411459)(Swift.Optional<Swift.UnsafeMutableRawPointer>) -> ()
}
runLoopSource = 0x0000000000446910 {
Foundation.NSObject = {}
_cfinfo = 9864
}
runLoop = 0x0000000000426d80 {
Foundation.NSObject = {}
_cfRunLoop = 0x00007fffe8000e00 {
Foundation.NSObject = {}
_cfinfo = 9088
}
}
processLaunchedCondition = {
Foundation.NSObject = {}
mutex = 0x00000000004468b0
cond = 0x00000000004454b0
name = nil
}
processIdentifier = 6177
isRunning = true
terminationStatus = 0
terminationReason = exit
terminationHandler = nil
qualityOfService = default
}
There are a few different consequences of this - I've found code in the wild that depends on this behavior.
Before I go any further, what's the correct/expected behavior here?