Skip to content

Commit e9ff528

Browse files
committed
Expand use of Win32Error
Have its string representation print the actual error message for improved debuggability.
1 parent ada40ac commit e9ff528

File tree

6 files changed

+54
-21
lines changed

6 files changed

+54
-21
lines changed

Sources/SWBUtil/CMakeLists.txt

+1
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,7 @@ add_library(SWBUtil
100100
VFS.swift
101101
WaitCondition.swift
102102
WeakRef.swift
103+
Win32Error.swift
103104
XCBuildDataArchive.swift
104105
Xcode.swift)
105106
set_target_properties(SWBUtil PROPERTIES

Sources/SWBUtil/FSProxy.swift

+5-12
Original file line numberDiff line numberDiff line change
@@ -621,15 +621,15 @@ class LocalFS: FSProxy, @unchecked Sendable {
621621
DWORD(OPEN_EXISTING), DWORD(FILE_FLAG_BACKUP_SEMANTICS), nil)
622622
}
623623
if handle == INVALID_HANDLE_VALUE {
624-
throw StubError.error("Failed to update file time")
624+
throw Win32Error(GetLastError())
625625
}
626626
try handle.closeAfter {
627627
var ft = FILETIME()
628628
var st = SYSTEMTIME()
629629
GetSystemTime(&st)
630630
SystemTimeToFileTime(&st, &ft)
631631
if !SetFileTime(handle, nil, &ft, &ft) {
632-
throw StubError.error("Failed to update file time")
632+
Win32Error(GetLastError())
633633
}
634634
}
635635
#else
@@ -648,7 +648,7 @@ class LocalFS: FSProxy, @unchecked Sendable {
648648
DWORD(OPEN_EXISTING), DWORD(FILE_FLAG_BACKUP_SEMANTICS), nil)
649649
}
650650
if handle == INVALID_HANDLE_VALUE {
651-
throw StubError.error("Failed to update file time")
651+
throw Win32Error(GetLastError())
652652
}
653653
try handle.closeAfter {
654654
// Number of 100ns intervals between 1601 and 1970 epochs
@@ -663,7 +663,7 @@ class LocalFS: FSProxy, @unchecked Sendable {
663663
ft.dwLowDateTime = timeInt.LowPart
664664
ft.dwHighDateTime = timeInt.HighPart
665665
if !SetFileTime(handle, nil, &ft, &ft) {
666-
throw StubError.error("Failed to update file time")
666+
throw Win32Error(GetLastError())
667667
}
668668
}
669669
#else
@@ -887,7 +887,7 @@ class LocalFS: FSProxy, @unchecked Sendable {
887887
return try withUnsafeTemporaryAllocation(of: WCHAR.self, capacity: Int(dwLength)) {
888888
guard GetFinalPathNameByHandleW(handle, $0.baseAddress!, DWORD($0.count),
889889
DWORD(FILE_NAME_NORMALIZED)) == dwLength - 1 else {
890-
throw StubError.error("GetFinalPathNameByHandleW failed")
890+
throw Win32Error(GetLastError())
891891
}
892892
let path = String(platformString: $0.baseAddress!)
893893
// Drop UNC prefix if present
@@ -1643,13 +1643,6 @@ extension HANDLE {
16431643
}
16441644
}
16451645
}
1646-
1647-
fileprivate struct Win32Error: Error {
1648-
let error: DWORD
1649-
init(_ error: DWORD) {
1650-
self.error = error
1651-
}
1652-
}
16531646
#endif
16541647

16551648
extension FileDescriptor {

Sources/SWBUtil/Library.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ public enum Library: Sendable {
3434
public static func open(_ path: Path) throws -> LibraryHandle {
3535
#if os(Windows)
3636
guard let handle = path.withPlatformString(LoadLibraryW) else {
37-
throw LibraryOpenError(message: "LoadLibraryW returned \(GetLastError())")
37+
throw LibraryOpenError(message: Win32Error(GetLastError()).description)
3838
}
3939
return LibraryHandle(rawValue: handle)
4040
#else

Sources/SWBUtil/Win32Error.swift

+39
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// This source file is part of the Swift open source project
4+
//
5+
// Copyright (c) 2025 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See http://swift.org/LICENSE.txt for license information
9+
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
#if os(Windows)
14+
public import WinSDK
15+
import Foundation
16+
17+
public struct Win32Error: Error, CustomStringConvertible {
18+
public let error: DWORD
19+
20+
public init(_ error: DWORD) {
21+
self.error = error
22+
}
23+
24+
public var description: String {
25+
let flags: DWORD = DWORD(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS)
26+
var buffer: UnsafeMutablePointer<WCHAR>?
27+
let length: DWORD = withUnsafeMutablePointer(to: &buffer) {
28+
$0.withMemoryRebound(to: WCHAR.self, capacity: 2) {
29+
FormatMessageW(flags, nil, error, 0, $0, 0, nil)
30+
}
31+
}
32+
guard let buffer, length > 0 else {
33+
return "Win32 Error Code \(error)"
34+
}
35+
defer { LocalFree(buffer) }
36+
return String(decodingCString: buffer, as: UTF16.self).trimmingCharacters(in: .whitespacesAndNewlines)
37+
}
38+
}
39+
#endif

Tests/SwiftBuildTests/ConsoleCommands/CLIConnection.swift

+6-6
Original file line numberDiff line numberDiff line change
@@ -165,11 +165,11 @@ final class CLIConnection {
165165
static func terminate(processIdentifier: Int32) throws {
166166
#if os(Windows)
167167
guard let proc = OpenProcess(DWORD(PROCESS_TERMINATE), false, DWORD(processIdentifier)) else {
168-
throw StubError.error("OpenProcess failed with error \(GetLastError())")
168+
throw Win32Error(GetLastError())
169169
}
170170
defer { CloseHandle(proc) }
171171
if !TerminateProcess(proc, UINT(0xC0000000 | DWORD(9))) {
172-
throw StubError.error("TerminateProcess returned \(GetLastError())")
172+
throw Win32Error(GetLastError())
173173
}
174174
#else
175175
if SWBLibc.kill(processIdentifier, SIGKILL) != 0 {
@@ -317,7 +317,7 @@ fileprivate func swiftRuntimePath() throws -> Path? {
317317
let name = "swiftCore.dll"
318318
return try name.withCString(encodedAs: CInterop.PlatformUnicodeEncoding.self) { wName in
319319
guard let handle = GetModuleHandleW(wName) else {
320-
throw POSIXError(errno, context: "GetModuleHandleW", name)
320+
throw Win32Error(GetLastError())
321321
}
322322

323323
var capacity = MAX_PATH
@@ -327,7 +327,7 @@ fileprivate func swiftRuntimePath() throws -> Path? {
327327
let dwLength = GetModuleFileNameW(handle, $0.baseAddress!, DWORD($0.count))
328328
switch dwLength {
329329
case 0:
330-
throw POSIXError(errno, context: "GetModuleFileNameW", String(dwLength))
330+
throw Win32Error(GetLastError())
331331
default:
332332
if GetLastError() == ERROR_INSUFFICIENT_BUFFER {
333333
capacity *= 2
@@ -348,12 +348,12 @@ fileprivate func systemRoot() throws -> Path? {
348348
#if os(Windows)
349349
let dwLength: DWORD = GetWindowsDirectoryW(nil, 0)
350350
if dwLength == 0 {
351-
throw POSIXError(errno, context: "GetWindowsDirectoryW")
351+
throw Win32Error(GetLastError())
352352
}
353353
return try withUnsafeTemporaryAllocation(of: WCHAR.self, capacity: Int(dwLength)) {
354354
switch GetWindowsDirectoryW($0.baseAddress!, DWORD($0.count)) {
355355
case 0:
356-
throw POSIXError(errno, context: "GetWindowsDirectoryW", String($0.count))
356+
throw Win32Error(GetLastError())
357357
default:
358358
return Path(String(decodingCString: $0.baseAddress!, as: CInterop.PlatformUnicodeEncoding.self))
359359
}

Tests/SwiftBuildTests/ConsoleCommands/ServiceConsoleTests.swift

+2-2
Original file line numberDiff line numberDiff line change
@@ -131,12 +131,12 @@ extension Processes {
131131
let promise = Promise<Void, any Error>()
132132
#if os(Windows)
133133
guard let proc: HANDLE = OpenProcess(SYNCHRONIZE, false, DWORD(pid)) else {
134-
throw StubError.error("OpenProcess failed with error \(GetLastError())")
134+
throw Win32Error(GetLastError())
135135
}
136136
defer { CloseHandle(proc) }
137137
Thread.detachNewThread {
138138
if WaitForSingleObject(proc, INFINITE) == WAIT_FAILED {
139-
promise.fail(throwing: StubError.error("WaitForSingleObject failed with error \(GetLastError())"))
139+
promise.fail(throwing: Win32Error(GetLastError()))
140140
return
141141
}
142142
promise.fulfill(with: ())

0 commit comments

Comments
 (0)