@@ -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
+ var dwExitCode : DWORD = DWORD ( bitPattern: - 1 )
98
+ do {
99
+ var hJob : HANDLE
97
100
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) }
101
+ hJob = CreateJobObjectA ( nil , nil )
102
+ if hJob == HANDLE ( bitPattern: 0 ) {
103
+ throw SystemError . exec ( Int32 ( GetLastError ( ) ) , path: path, args: args)
104
+ }
105
+ defer { CloseHandle ( hJob) }
103
106
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
- }
107
+ let hPort = CreateIoCompletionPort ( INVALID_HANDLE_VALUE, nil , 0 , 1 )
108
+ if hPort == HANDLE ( bitPattern: 0 ) {
109
+ throw SystemError . exec ( Int32 ( GetLastError ( ) ) , path: path, args: args)
110
+ }
108
111
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
- }
112
+ var acpAssociation : JOBOBJECT_ASSOCIATE_COMPLETION_PORT = JOBOBJECT_ASSOCIATE_COMPLETION_PORT ( )
113
+ acpAssociation. CompletionKey = hJob
114
+ acpAssociation. CompletionPort = hPort
115
+ if !SetInformationJobObject( hJob, JobObjectAssociateCompletionPortInformation,
116
+ & acpAssociation, DWORD ( MemoryLayout< JOBOBJECT_ASSOCIATE_COMPLETION_PORT> . size) ) {
117
+ throw SystemError . exec ( Int32 ( GetLastError ( ) ) , path: path, args: args)
118
+ }
116
119
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
- }
120
+ var eliLimits : JOBOBJECT_EXTENDED_LIMIT_INFORMATION = JOBOBJECT_EXTENDED_LIMIT_INFORMATION ( )
121
+ eliLimits. BasicLimitInformation. LimitFlags =
122
+ DWORD ( JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE) | DWORD ( JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK)
123
+ if !SetInformationJobObject( hJob, JobObjectExtendedLimitInformation, & eliLimits,
124
+ DWORD ( MemoryLayout< JOBOBJECT_EXTENDED_LIMIT_INFORMATION> . size) ) {
125
+ throw SystemError . exec ( Int32 ( GetLastError ( ) ) , path: path, args: args)
126
+ }
124
127
125
128
126
- var siInfo : STARTUPINFOW = STARTUPINFOW ( )
127
- siInfo. cb = DWORD ( MemoryLayout< STARTUPINFOW> . size)
129
+ var siInfo : STARTUPINFOW = STARTUPINFOW ( )
130
+ siInfo. cb = DWORD ( MemoryLayout< STARTUPINFOW> . size)
128
131
129
- var piInfo : PROCESS_INFORMATION = PROCESS_INFORMATION ( )
132
+ var piInfo : PROCESS_INFORMATION = PROCESS_INFORMATION ( )
130
133
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)
134
+ try quote ( args) . withCString ( encodedAs: UTF16 . self) { pwszCommandLine in
135
+ if !CreateProcessW( nil ,
136
+ UnsafeMutablePointer < WCHAR > ( mutating: pwszCommandLine) ,
137
+ nil , nil , false ,
138
+ DWORD ( CREATE_SUSPENDED) | DWORD ( CREATE_NEW_PROCESS_GROUP) ,
139
+ nil , nil , & siInfo, & piInfo) {
140
+ throw SystemError . exec ( Int32 ( GetLastError ( ) ) , path: path, args: args)
141
+ }
138
142
}
139
- }
140
143
141
- defer { CloseHandle ( piInfo. hThread) }
142
- defer { CloseHandle ( piInfo. hProcess) }
144
+ defer { CloseHandle ( piInfo. hThread) }
145
+ defer { CloseHandle ( piInfo. hProcess) }
143
146
144
- if !AssignProcessToJobObject( hJob, piInfo. hProcess) {
145
- throw SystemError . exec ( Int32 ( GetLastError ( ) ) , path: path, args: args)
146
- }
147
+ if !AssignProcessToJobObject( hJob, piInfo. hProcess) {
148
+ throw SystemError . exec ( Int32 ( GetLastError ( ) ) , path: path, args: args)
149
+ }
147
150
148
- _ = ResumeThread ( piInfo. hThread)
151
+ _ = ResumeThread ( piInfo. hThread)
149
152
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)
153
+ var dwCompletionCode : DWORD = 0
154
+ var ulCompletionKey : ULONG_PTR = 0
155
+ var lpOverlapped : LPOVERLAPPED ?
156
+ repeat {
157
+ } while GetQueuedCompletionStatus ( hPort, & dwCompletionCode, & ulCompletionKey,
158
+ & lpOverlapped, INFINITE) &&
159
+ !( ulCompletionKey == ULONG_PTR ( UInt ( bitPattern: hJob) ) &&
160
+ dwCompletionCode == JOB_OBJECT_MSG_ACTIVE_PROCESS_ZERO)
158
161
159
- var dwExitCode : DWORD = DWORD ( bitPattern : - 1 )
160
- _ = GetExitCodeProcess ( piInfo . hProcess , & dwExitCode )
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