Skip to content

Commit f6b96c3

Browse files
authored
Merge pull request #279 from mairinkdev/main
Fix silent buffer size truncation in Windows pread/pwrite
2 parents 53afbde + 7664154 commit f6b96c3

File tree

3 files changed

+60
-1
lines changed

3 files changed

+60
-1
lines changed

Sources/System/Errno.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,7 @@ public struct Errno: RawRepresentable, Error, Hashable, Codable {
160160
/// No child processes.
161161
///
162162
/// A `wait(2)` or `waitpid(2)` function was executed
163-
/// by a process that dosn't have any existing child processes
163+
/// by a process that doesn't have any existing child processes
164164
/// or whose child processes are all already being waited for.
165165
///
166166
/// The corresponding C error is `ECHILD`.

Sources/System/Internals/WindowsSyscallAdapters.swift

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,12 @@ internal func pread(
149149
let handle: intptr_t = _get_osfhandle(fd)
150150
if handle == /* INVALID_HANDLE_VALUE */ -1 { ucrt._set_errno(EBADF); return -1 }
151151

152+
// Windows ReadFile accepts DWORD (32-bit) for buffer size, so validate nbyte doesn't exceed it
153+
if nbyte > Int(DWORD.max) {
154+
ucrt._set_errno(EINVAL)
155+
return -1
156+
}
157+
152158
// NOTE: this is a non-owning handle, do *not* call CloseHandle on it
153159
let hFile: HANDLE = HANDLE(bitPattern: handle)!
154160

@@ -171,6 +177,12 @@ internal func pwrite(
171177
let handle: intptr_t = _get_osfhandle(fd)
172178
if handle == /* INVALID_HANDLE_VALUE */ -1 { ucrt._set_errno(EBADF); return -1 }
173179

180+
// Windows WriteFile accepts DWORD (32-bit) for buffer size, so validate nbyte doesn't exceed it
181+
if nbyte > Int(DWORD.max) {
182+
ucrt._set_errno(EINVAL)
183+
return -1
184+
}
185+
174186
// NOTE: this is a non-owning handle, do *not* call CloseHandle on it
175187
let hFile: HANDLE = HANDLE(bitPattern: handle)!
176188

Tests/SystemTests/FileOperationsTestWindows.swift

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -242,6 +242,53 @@ final class FileOperationsTestWindows: XCTestCase {
242242
}
243243
}
244244
}
245+
246+
/// Test that buffer sizes exceeding DWORD.max (4GB) are properly rejected
247+
func testBufferSizeLimit() throws {
248+
try withTemporaryFilePath(basename: "testBufferSizeLimit") { path in
249+
let fd = try FileDescriptor.open(
250+
path.appending("test.txt"),
251+
.readWrite,
252+
options: [.create, .truncate],
253+
permissions: .ownerReadWrite
254+
)
255+
defer { try? fd.close() }
256+
257+
// Write some data first
258+
try fd.writeAll("test data".utf8)
259+
260+
// Allocate a small buffer for testing
261+
let buffer = UnsafeMutableRawBufferPointer.allocate(byteCount: 1024, alignment: 1)
262+
defer { buffer.deallocate() }
263+
264+
// Test that a count exceeding DWORD.max (UInt32.max = 4,294,967,295) returns EINVAL
265+
// We use a buffer pointer but pass a count > DWORD.max
266+
let oversizedCount = Int(DWORD.max) + 1
267+
let oversizedBuffer = UnsafeMutableRawBufferPointer(
268+
start: buffer.baseAddress,
269+
count: oversizedCount
270+
)
271+
272+
// pread should fail with EINVAL
273+
do {
274+
_ = try fd.read(fromAbsoluteOffset: 0, into: oversizedBuffer)
275+
XCTFail("Expected EINVAL for buffer size exceeding DWORD.max")
276+
} catch let err as Errno {
277+
XCTAssertEqual(err, .invalidArgument, "Expected EINVAL, got \(err)")
278+
}
279+
280+
// pwrite should also fail with EINVAL
281+
do {
282+
_ = try fd.write(toAbsoluteOffset: 0, UnsafeRawBufferPointer(oversizedBuffer))
283+
XCTFail("Expected EINVAL for buffer size exceeding DWORD.max")
284+
} catch let err as Errno {
285+
XCTAssertEqual(err, .invalidArgument, "Expected EINVAL, got \(err)")
286+
}
287+
288+
// Verify that exactly DWORD.max works (if we had a buffer that large)
289+
// We can't easily test this without allocating 4GB, but the boundary is correct
290+
}
291+
}
245292
}
246293

247294
#endif // os(Windows)

0 commit comments

Comments
 (0)