@@ -93,71 +93,74 @@ private func quote(_ arguments: [String]) -> String {
93
93
public func exec( path: String , args: [ String ] ) throws -> Never {
94
94
let cArgs = CStringArray ( args)
95
95
#if os(Windows)
96
- var hJob : HANDLE
96
+ // Wrap body in a do block to ensure closing handles in defer blocks occurs prior to the call to _exit
97
+ do {
98
+ var hJob : HANDLE
97
99
98
- hJob = CreateJobObjectA ( nil , nil )
99
- if hJob == HANDLE ( bitPattern: 0 ) {
100
- throw SystemError . exec ( Int32 ( GetLastError ( ) ) , path: path, args: args)
101
- }
102
- defer { CloseHandle ( hJob) }
100
+ hJob = CreateJobObjectA ( nil , nil )
101
+ if hJob == HANDLE ( bitPattern: 0 ) {
102
+ throw SystemError . exec ( Int32 ( GetLastError ( ) ) , path: path, args: args)
103
+ }
104
+ defer { CloseHandle ( hJob) }
103
105
104
- let hPort = CreateIoCompletionPort ( INVALID_HANDLE_VALUE, nil , 0 , 1 )
105
- if hPort == HANDLE ( bitPattern: 0 ) {
106
- throw SystemError . exec ( Int32 ( GetLastError ( ) ) , path: path, args: args)
107
- }
106
+ let hPort = CreateIoCompletionPort ( INVALID_HANDLE_VALUE, nil , 0 , 1 )
107
+ if hPort == HANDLE ( bitPattern: 0 ) {
108
+ throw SystemError . exec ( Int32 ( GetLastError ( ) ) , path: path, args: args)
109
+ }
108
110
109
- var acpAssociation : JOBOBJECT_ASSOCIATE_COMPLETION_PORT = JOBOBJECT_ASSOCIATE_COMPLETION_PORT ( )
110
- acpAssociation. CompletionKey = hJob
111
- acpAssociation. CompletionPort = hPort
112
- if !SetInformationJobObject( hJob, JobObjectAssociateCompletionPortInformation,
113
- & acpAssociation, DWORD ( MemoryLayout< JOBOBJECT_ASSOCIATE_COMPLETION_PORT> . size) ) {
114
- throw SystemError . exec ( Int32 ( GetLastError ( ) ) , path: path, args: args)
115
- }
111
+ var acpAssociation : JOBOBJECT_ASSOCIATE_COMPLETION_PORT = JOBOBJECT_ASSOCIATE_COMPLETION_PORT ( )
112
+ acpAssociation. CompletionKey = hJob
113
+ acpAssociation. CompletionPort = hPort
114
+ if !SetInformationJobObject( hJob, JobObjectAssociateCompletionPortInformation,
115
+ & acpAssociation, DWORD ( MemoryLayout< JOBOBJECT_ASSOCIATE_COMPLETION_PORT> . size) ) {
116
+ throw SystemError . exec ( Int32 ( GetLastError ( ) ) , path: path, args: args)
117
+ }
116
118
117
- var eliLimits : JOBOBJECT_EXTENDED_LIMIT_INFORMATION = JOBOBJECT_EXTENDED_LIMIT_INFORMATION ( )
118
- eliLimits. BasicLimitInformation. LimitFlags =
119
- DWORD ( JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE) | DWORD ( JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK)
120
- if !SetInformationJobObject( hJob, JobObjectExtendedLimitInformation, & eliLimits,
121
- DWORD ( MemoryLayout< JOBOBJECT_EXTENDED_LIMIT_INFORMATION> . size) ) {
122
- throw SystemError . exec ( Int32 ( GetLastError ( ) ) , path: path, args: args)
123
- }
119
+ var eliLimits : JOBOBJECT_EXTENDED_LIMIT_INFORMATION = JOBOBJECT_EXTENDED_LIMIT_INFORMATION ( )
120
+ eliLimits. BasicLimitInformation. LimitFlags =
121
+ DWORD ( JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE) | DWORD ( JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK)
122
+ if !SetInformationJobObject( hJob, JobObjectExtendedLimitInformation, & eliLimits,
123
+ DWORD ( MemoryLayout< JOBOBJECT_EXTENDED_LIMIT_INFORMATION> . size) ) {
124
+ throw SystemError . exec ( Int32 ( GetLastError ( ) ) , path: path, args: args)
125
+ }
124
126
125
127
126
- var siInfo : STARTUPINFOW = STARTUPINFOW ( )
127
- siInfo. cb = DWORD ( MemoryLayout< STARTUPINFOW> . size)
128
+ var siInfo : STARTUPINFOW = STARTUPINFOW ( )
129
+ siInfo. cb = DWORD ( MemoryLayout< STARTUPINFOW> . size)
128
130
129
- var piInfo : PROCESS_INFORMATION = PROCESS_INFORMATION ( )
131
+ var piInfo : PROCESS_INFORMATION = PROCESS_INFORMATION ( )
130
132
131
- try quote ( args) . withCString ( encodedAs: UTF16 . self) { pwszCommandLine in
132
- if !CreateProcessW( nil ,
133
- UnsafeMutablePointer < WCHAR > ( mutating: pwszCommandLine) ,
134
- nil , nil , false ,
135
- DWORD ( CREATE_SUSPENDED) | DWORD ( CREATE_NEW_PROCESS_GROUP) ,
136
- nil , nil , & siInfo, & piInfo) {
137
- throw SystemError . exec ( Int32 ( GetLastError ( ) ) , path: path, args: args)
133
+ try quote ( args) . withCString ( encodedAs: UTF16 . self) { pwszCommandLine in
134
+ if !CreateProcessW( nil ,
135
+ UnsafeMutablePointer < WCHAR > ( mutating: pwszCommandLine) ,
136
+ nil , nil , false ,
137
+ DWORD ( CREATE_SUSPENDED) | DWORD ( CREATE_NEW_PROCESS_GROUP) ,
138
+ nil , nil , & siInfo, & piInfo) {
139
+ throw SystemError . exec ( Int32 ( GetLastError ( ) ) , path: path, args: args)
140
+ }
138
141
}
139
- }
140
142
141
- defer { CloseHandle ( piInfo. hThread) }
142
- defer { CloseHandle ( piInfo. hProcess) }
143
+ defer { CloseHandle ( piInfo. hThread) }
144
+ defer { CloseHandle ( piInfo. hProcess) }
143
145
144
- if !AssignProcessToJobObject( hJob, piInfo. hProcess) {
145
- throw SystemError . exec ( Int32 ( GetLastError ( ) ) , path: path, args: args)
146
- }
146
+ if !AssignProcessToJobObject( hJob, piInfo. hProcess) {
147
+ throw SystemError . exec ( Int32 ( GetLastError ( ) ) , path: path, args: args)
148
+ }
147
149
148
- _ = ResumeThread ( piInfo. hThread)
150
+ _ = ResumeThread ( piInfo. hThread)
149
151
150
- var dwCompletionCode : DWORD = 0
151
- var ulCompletionKey : ULONG_PTR = 0
152
- var lpOverlapped : LPOVERLAPPED ?
153
- repeat {
154
- } while GetQueuedCompletionStatus ( hPort, & dwCompletionCode, & ulCompletionKey,
155
- & lpOverlapped, INFINITE) &&
156
- !( ulCompletionKey == ULONG_PTR ( UInt ( bitPattern: hJob) ) &&
157
- dwCompletionCode == JOB_OBJECT_MSG_ACTIVE_PROCESS_ZERO)
152
+ var dwCompletionCode : DWORD = 0
153
+ var ulCompletionKey : ULONG_PTR = 0
154
+ var lpOverlapped : LPOVERLAPPED ?
155
+ repeat {
156
+ } while GetQueuedCompletionStatus ( hPort, & dwCompletionCode, & ulCompletionKey,
157
+ & lpOverlapped, INFINITE) &&
158
+ !( ulCompletionKey == ULONG_PTR ( UInt ( bitPattern: hJob) ) &&
159
+ dwCompletionCode == JOB_OBJECT_MSG_ACTIVE_PROCESS_ZERO)
158
160
159
- var dwExitCode : DWORD = DWORD ( bitPattern: - 1 )
160
- _ = GetExitCodeProcess ( piInfo. hProcess, & dwExitCode)
161
+ var dwExitCode : DWORD = DWORD ( bitPattern: - 1 )
162
+ _ = GetExitCodeProcess ( piInfo. hProcess, & dwExitCode)
163
+ }
161
164
_exit ( Int32 ( bitPattern: dwExitCode) )
162
165
#elseif (!canImport(Darwin) || os(macOS))
163
166
guard execv ( path, cArgs. cArray) != - 1 else {
0 commit comments