@@ -241,7 +241,11 @@ open class Process: NSObject {
241
241
open func run( ) throws {
242
242
243
243
self . processLaunchedCondition. lock ( )
244
-
244
+ defer {
245
+ self . processLaunchedCondition. unlock ( )
246
+ self . processLaunchedCondition. broadcast ( )
247
+ }
248
+
245
249
// Dispatch the manager thread if it isn't already running
246
250
247
251
Process . setup ( )
@@ -250,7 +254,23 @@ open class Process: NSObject {
250
254
guard let launchPath = self . executableURL? . path else {
251
255
throw NSError ( domain: NSCocoaErrorDomain, code: NSFileNoSuchFileError)
252
256
}
253
-
257
+
258
+ // Initial checks that the launchPath points to an executable file. posix_spawn()
259
+ // can return success even if executing the program fails, eg fork() works but execve()
260
+ // fails, so try and check as much as possible beforehand.
261
+ try FileManager . default. _fileSystemRepresentation ( withPath: launchPath, { fsRep in
262
+ var statInfo = stat ( )
263
+ guard stat ( fsRep, & statInfo) == 0 else {
264
+ throw _NSErrorWithErrno ( errno, reading: true , path: launchPath)
265
+ }
266
+
267
+ guard statInfo. st_mode & S_IFMT == S_IFREG else {
268
+ throw NSError ( domain: NSCocoaErrorDomain, code: NSFileNoSuchFileError)
269
+ }
270
+ guard access ( fsRep, X_OK) == 0 else {
271
+ throw _NSErrorWithErrno ( errno, reading: true , path: launchPath)
272
+ }
273
+ } )
254
274
// Convert the arguments array into a posix_spawn-friendly format
255
275
256
276
var args = [ launchPath]
@@ -452,7 +472,7 @@ open class Process: NSObject {
452
472
}
453
473
454
474
close ( taskSocketPair [ 1 ] )
455
-
475
+
456
476
self . runLoop = RunLoop . current
457
477
self . runLoopSourceContext = CFRunLoopSourceContext ( version: 0 ,
458
478
info: Unmanaged . passUnretained ( self ) . toOpaque ( ) ,
@@ -484,9 +504,6 @@ open class Process: NSObject {
484
504
isRunning = true
485
505
486
506
self . processIdentifier = pid
487
-
488
- self . processLaunchedCondition. unlock ( )
489
- self . processLaunchedCondition. broadcast ( )
490
507
}
491
508
492
509
open func interrupt( ) { NSUnimplemented ( ) } // Not always possible. Sends SIGINT.
0 commit comments