From 09d8384cd68c7343f0ea01d6ad9f3b74ebc99f07 Mon Sep 17 00:00:00 2001 From: broken-circle <252359939+broken-circle@users.noreply.github.com> Date: Mon, 8 Jun 2026 10:18:03 -0700 Subject: [PATCH] Fix crash in `fillNullTerminatedWideStringBuffer()` The function passed a typed-throwing closure to `withUnsafeTemporaryAllocation()`, whose closure parameter is `rethrows`. Bridging the typed throw into `rethrows` miscompiles under release optimization on the Swift 6.2.x Windows toolchain and crashes; debug builds and nightly-main are unaffected. Restructure so the allocation closure no longer throws. Instead, it returns a result enum, and the enclosing loop throws or grows the buffer accordingly. This drops the typed-throws-into-`rethrows` bridge, which in turn drops the `#if swift(>=6.3)` workaround guarding the same path and allows `body` to be non-throwing, since no caller throws from it. Also remove `assert()`; the package avoids its use everwhere. Behavior is otherwise unchanged. --- .../Platforms/Subprocess+Windows.swift | 58 ++++++++++--------- 1 file changed, 32 insertions(+), 26 deletions(-) diff --git a/Sources/Subprocess/Platforms/Subprocess+Windows.swift b/Sources/Subprocess/Platforms/Subprocess+Windows.swift index e511652a..9668ccaa 100644 --- a/Sources/Subprocess/Platforms/Subprocess+Windows.swift +++ b/Sources/Subprocess/Platforms/Subprocess+Windows.swift @@ -1691,36 +1691,42 @@ extension UInt8 { internal func fillNullTerminatedWideStringBuffer( initialSize: DWORD, maxSize: DWORD, - _ body: (UnsafeMutableBufferPointer) throws(SubprocessError.WindowsError) -> DWORD + _ body: (UnsafeMutableBufferPointer) -> DWORD ) throws(SubprocessError.WindowsError) -> String { + enum FillResult { + case filled(String) + case insufficient + case failed(DWORD) + } var bufferCount = max(1, min(initialSize, maxSize)) while bufferCount <= maxSize { - do { - if let result = try withUnsafeTemporaryAllocation( - of: WCHAR.self, capacity: Int(bufferCount), - { buffer throws(SubprocessError.WindowsError) in - let count = try body(buffer) - switch count { - case 0: - throw SubprocessError.WindowsError(win32Error: GetLastError()) - case 1..=6.3) - throw error - #else - throw error as! SubprocessError.WindowsError - #endif + } + switch result { + case .filled(let string): + return string + case .failed(let win32Error): + throw SubprocessError.WindowsError(win32Error: win32Error) + case .insufficient: + bufferCount *= 2 } } throw SubprocessError.WindowsError(win32Error: DWORD(ERROR_INSUFFICIENT_BUFFER))