@@ -157,17 +157,25 @@ extension Configuration {
157157    @available ( SubprocessSpan,  * )  
158158    #endif 
159159    internal  func  spawn( 
160-         withInput inputPipe:  CreatedPipe , 
161-         outputPipe:  CreatedPipe , 
162-         errorPipe:  CreatedPipe 
163-     )  throws  ->  Execution  { 
160+         withInput inputPipe:  consuming   CreatedPipe , 
161+         outputPipe:  consuming   CreatedPipe , 
162+         errorPipe:  consuming   CreatedPipe 
163+     )  throws  ->  SpawnResult  { 
164164        // Instead of checking if every possible executable path
165165        // is valid, spawn each directly and catch ENOENT
166166        let  possiblePaths  =  self . executable. possibleExecutablePaths ( 
167167            withPathValue:  self . environment. pathValue ( ) 
168168        ) 
169-         return  try   self . preSpawn  {  args throws  ->  Execution  in 
169+         var  inputPipeBox :  CreatedPipe ? ?   =  consume inputPipe
170+         var  outputPipeBox :  CreatedPipe ? ?   =  consume outputPipe
171+         var  errorPipeBox :  CreatedPipe ? ?   =  consume errorPipe
172+ 
173+         return  try   self . preSpawn  {  args throws  ->  SpawnResult  in 
170174            let  ( env,  uidPtr,  gidPtr,  supplementaryGroups)  =  args
175+             let  _inputPipe  =  inputPipeBox!. take ( ) !
176+             let  _outputPipe  =  outputPipeBox!. take ( ) !
177+             let  _errorPipe  =  errorPipeBox!. take ( ) !
178+ 
171179            for  possibleExecutablePath  in  possiblePaths { 
172180                var  pid :  pid_t  =  0 
173181
@@ -187,67 +195,68 @@ extension Configuration {
187195                defer  { 
188196                    posix_spawn_file_actions_destroy ( & fileActions) 
189197                } 
198+ 
190199                // Input
191200                var  result :  Int32  =  - 1 
192-                 if  let  inputRead =  inputPipe . readFileDescriptor { 
201+                 if  let  inputRead =  _inputPipe . readFileDescriptor { 
193202                    result =  posix_spawn_file_actions_adddup2 ( & fileActions,  inputRead. platformDescriptor,  0 ) 
194203                    guard  result ==  0  else  { 
195-                         try   self . cleanupPreSpawn ( input:  inputPipe ,  output:  outputPipe ,  error:  errorPipe ) 
204+                         try   self . cleanupPreSpawn ( input:  _inputPipe ,  output:  _outputPipe ,  error:  _errorPipe ) 
196205                        throw  SubprocessError ( 
197206                            code:  . init( . spawnFailed) , 
198207                            underlyingError:  . init( rawValue:  result) 
199208                        ) 
200209                    } 
201210                } 
202-                 if  let  inputWrite =  inputPipe . writeFileDescriptor { 
211+                 if  let  inputWrite =  _inputPipe . writeFileDescriptor { 
203212                    // Close parent side
204213                    result =  posix_spawn_file_actions_addclose ( & fileActions,  inputWrite. platformDescriptor) 
205214                    guard  result ==  0  else  { 
206-                         try   self . cleanupPreSpawn ( input:  inputPipe ,  output:  outputPipe ,  error:  errorPipe ) 
215+                         try   self . cleanupPreSpawn ( input:  _inputPipe ,  output:  _outputPipe ,  error:  _errorPipe ) 
207216                        throw  SubprocessError ( 
208217                            code:  . init( . spawnFailed) , 
209218                            underlyingError:  . init( rawValue:  result) 
210219                        ) 
211220                    } 
212221                } 
213222                // Output
214-                 if  let  outputWrite =  outputPipe . writeFileDescriptor { 
223+                 if  let  outputWrite =  _outputPipe . writeFileDescriptor { 
215224                    result =  posix_spawn_file_actions_adddup2 ( & fileActions,  outputWrite. platformDescriptor,  1 ) 
216225                    guard  result ==  0  else  { 
217-                         try   self . cleanupPreSpawn ( input:  inputPipe ,  output:  outputPipe ,  error:  errorPipe ) 
226+                         try   self . cleanupPreSpawn ( input:  _inputPipe ,  output:  _outputPipe ,  error:  _errorPipe ) 
218227                        throw  SubprocessError ( 
219228                            code:  . init( . spawnFailed) , 
220229                            underlyingError:  . init( rawValue:  result) 
221230                        ) 
222231                    } 
223232                } 
224-                 if  let  outputRead =  outputPipe . readFileDescriptor { 
233+                 if  let  outputRead =  _outputPipe . readFileDescriptor { 
225234                    // Close parent side
226235                    result =  posix_spawn_file_actions_addclose ( & fileActions,  outputRead. platformDescriptor) 
227236                    guard  result ==  0  else  { 
228-                         try   self . cleanupPreSpawn ( input:  inputPipe ,  output:  outputPipe ,  error:  errorPipe ) 
237+                         try   self . cleanupPreSpawn ( input:  _inputPipe ,  output:  _outputPipe ,  error:  _errorPipe ) 
229238                        throw  SubprocessError ( 
230239                            code:  . init( . spawnFailed) , 
231240                            underlyingError:  . init( rawValue:  result) 
232241                        ) 
233242                    } 
234243                } 
235244                // Error
236-                 if  let  errorWrite =  errorPipe . writeFileDescriptor { 
245+                 if  let  errorWrite =  _errorPipe . writeFileDescriptor { 
237246                    result =  posix_spawn_file_actions_adddup2 ( & fileActions,  errorWrite. platformDescriptor,  2 ) 
238247                    guard  result ==  0  else  { 
239-                         try   self . cleanupPreSpawn ( input:  inputPipe ,  output:  outputPipe ,  error:  errorPipe ) 
248+                         try   self . cleanupPreSpawn ( input:  _inputPipe ,  output:  _outputPipe ,  error:  _errorPipe ) 
240249                        throw  SubprocessError ( 
241250                            code:  . init( . spawnFailed) , 
242251                            underlyingError:  . init( rawValue:  result) 
243252                        ) 
244253                    } 
245254                } 
246-                 if  let  errorRead =  errorPipe . readFileDescriptor { 
255+                 if  let  errorRead =  _errorPipe . readFileDescriptor { 
247256                    // Close parent side
248257                    result =  posix_spawn_file_actions_addclose ( & fileActions,  errorRead. platformDescriptor) 
249258                    guard  result ==  0  else  { 
250-                         try   self . cleanupPreSpawn ( input:  inputPipe ,  output:  outputPipe ,  error:  errorPipe ) 
259+                         try   self . cleanupPreSpawn ( input:  _inputPipe ,  output:  _outputPipe ,  error:  _errorPipe ) 
251260                        throw  SubprocessError ( 
252261                            code:  . init( . spawnFailed) , 
253262                            underlyingError:  . init( rawValue:  result) 
@@ -290,7 +299,7 @@ extension Configuration {
290299
291300                // Error handling
292301                if  chdirError !=  0  || spawnAttributeError !=  0  { 
293-                     try   self . cleanupPreSpawn ( input:  inputPipe ,  output:  outputPipe ,  error:  errorPipe ) 
302+                     try   self . cleanupPreSpawn ( input:  _inputPipe ,  output:  _outputPipe ,  error:  _errorPipe ) 
294303                    if  spawnAttributeError !=  0  { 
295304                        throw  SubprocessError ( 
296305                            code:  . init( . spawnFailed) , 
@@ -336,34 +345,36 @@ extension Configuration {
336345                    } 
337346                    // Throw all other errors
338347                    try   self . cleanupPreSpawn ( 
339-                         input:  inputPipe , 
340-                         output:  outputPipe , 
341-                         error:  errorPipe 
348+                         input:  _inputPipe , 
349+                         output:  _outputPipe , 
350+                         error:  _errorPipe 
342351                    ) 
343352                    throw  SubprocessError ( 
344353                        code:  . init( . spawnFailed) , 
345354                        underlyingError:  . init( rawValue:  spawnError) 
346355                    ) 
347356                } 
348357
349-                 func  captureError( _ work:  ( )  throws  ->  Void )  ->  ( any  Swift . Error ) ?   { 
350-                     do  { 
351-                         try   work ( ) 
352-                         return  nil 
353-                     }  catch  { 
354-                         return  error
355-                     } 
356-                 } 
357358                // After spawn finishes, close all child side fds
358-                 let  inputCloseError  =  captureError  { 
359-                     try   inputPipe. readFileDescriptor? . safelyClose ( ) 
359+                 var  inputCloseError :  ( any  Swift . Error ) ?   =  nil 
360+                 do  { 
361+                     try   _inputPipe. readFileDescriptor? . safelyClose ( ) 
362+                 }  catch  { 
363+                     inputCloseError =  error
360364                } 
361-                 let  outputCloseError  =  captureError  { 
362-                     try   outputPipe. writeFileDescriptor? . safelyClose ( ) 
365+                 var  outputCloseError :  ( any  Swift . Error ) ?   =  nil 
366+                 do  { 
367+                     try   _outputPipe. writeFileDescriptor? . safelyClose ( ) 
368+                 }  catch  { 
369+                     outputCloseError =  error
363370                } 
364-                 let  errorCloseError  =  captureError  { 
365-                     try   errorPipe. writeFileDescriptor? . safelyClose ( ) 
371+                 var  errorCloseError :  ( any  Swift . Error ) ?   =  nil 
372+                 do  { 
373+                     try   _errorPipe. writeFileDescriptor? . safelyClose ( ) 
374+                 }  catch  { 
375+                     errorCloseError =  error
366376                } 
377+ 
367378                if  let  inputCloseError =  inputCloseError { 
368379                    throw  inputCloseError
369380                } 
@@ -374,17 +385,23 @@ extension Configuration {
374385                    throw  errorCloseError
375386                } 
376387
377-                 return  Execution ( 
388+                 let   execution   =  Execution ( 
378389                    processIdentifier:  . init( value:  pid) 
379390                ) 
391+                 return  SpawnResult ( 
392+                     execution:  execution, 
393+                     inputPipe:  _inputPipe, 
394+                     outputPipe:  _outputPipe, 
395+                     errorPipe:  _errorPipe
396+                 ) 
380397            } 
381398
382399            // If we reach this point, it means either the executable path
383400            // or working directory is not valid. Since posix_spawn does not
384401            // provide which one is not valid, here we make a best effort guess
385402            // by checking whether the working directory is valid. This technically
386403            // still causes TOUTOC issue, but it's the best we can do for error recovery.
387-             try   self . cleanupPreSpawn ( input:  inputPipe ,  output:  outputPipe ,  error:  errorPipe ) 
404+             try   self . cleanupPreSpawn ( input:  _inputPipe ,  output:  _outputPipe ,  error:  _errorPipe ) 
388405            let  workingDirectory  =  self . workingDirectory. string
389406            guard  Configuration . pathAccessible ( workingDirectory,  mode:  F_OK)  else  { 
390407                throw  SubprocessError ( 
0 commit comments