@@ -93,71 +93,74 @@ private func quote(_ arguments: [String]) -> String {
9393public func exec( path: String , args: [ String ] ) throws -> Never {
9494 let cArgs = CStringArray ( args)
9595 #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
97100
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) }
103106
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+ }
108111
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+ }
116119
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+ }
124127
125128
126- var siInfo : STARTUPINFOW = STARTUPINFOW ( )
127- siInfo. cb = DWORD ( MemoryLayout< STARTUPINFOW> . size)
129+ var siInfo : STARTUPINFOW = STARTUPINFOW ( )
130+ siInfo. cb = DWORD ( MemoryLayout< STARTUPINFOW> . size)
128131
129- var piInfo : PROCESS_INFORMATION = PROCESS_INFORMATION ( )
132+ var piInfo : PROCESS_INFORMATION = PROCESS_INFORMATION ( )
130133
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+ }
138142 }
139- }
140143
141- defer { CloseHandle ( piInfo. hThread) }
142- defer { CloseHandle ( piInfo. hProcess) }
144+ defer { CloseHandle ( piInfo. hThread) }
145+ defer { CloseHandle ( piInfo. hProcess) }
143146
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+ }
147150
148- _ = ResumeThread ( piInfo. hThread)
151+ _ = ResumeThread ( piInfo. hThread)
149152
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)
158161
159- var dwExitCode : DWORD = DWORD ( bitPattern : - 1 )
160- _ = GetExitCodeProcess ( piInfo . hProcess , & dwExitCode )
162+ _ = GetExitCodeProcess ( piInfo . hProcess , & dwExitCode )
163+ }
161164 _exit ( Int32 ( bitPattern: dwExitCode) )
162165 #elseif (!canImport(Darwin) || os(macOS))
163166 guard execv ( path, cArgs. cArray) != - 1 else {
0 commit comments