cap read+pread POSIX read sizes at Int32.max (#2323)
Cap NonBlockingFileIO reads at Int32.max Motivation: We wish to avoid overly large reads resulting in EINVAL signals being triggered resulting in errors. We workaround the issiue in the NonBlockingFileIO level to keep the lower levels as simple as possible. Modifications: `NonBlockingFileIO` `read0` amends read `byteCount`s to be `Int32.max` if they are larger than that value. Result: Large `NonBlockingFileIO` reads no longer result in precondition failures.
This commit is contained in:
parent
597fa409ee
commit
00341c9277
|
@ -435,12 +435,13 @@ public struct NonBlockingFileIO: Sendable {
|
|||
|
||||
private func read0(fileHandle: NIOFileHandle,
|
||||
fromOffset: Int64?, // > 2 GB offset is reasonable on 32-bit systems
|
||||
byteCount: Int,
|
||||
byteCount rawByteCount: Int,
|
||||
allocator: ByteBufferAllocator,
|
||||
eventLoop: EventLoop) -> EventLoopFuture<ByteBuffer> {
|
||||
guard byteCount > 0 else {
|
||||
guard rawByteCount > 0 else {
|
||||
return eventLoop.makeSucceededFuture(allocator.buffer(capacity: 0))
|
||||
}
|
||||
let byteCount = rawByteCount < Int32.max ? rawByteCount : size_t(Int32.max)
|
||||
|
||||
var buf = allocator.buffer(capacity: byteCount)
|
||||
return self.threadPool.runIfActive(eventLoop: eventLoop) { () -> ByteBuffer in
|
||||
|
|
|
@ -40,6 +40,7 @@ extension NonBlockingFileIOTest {
|
|||
("testReadingDifferentChunkSize", testReadingDifferentChunkSize),
|
||||
("testReadDoesNotReadShort", testReadDoesNotReadShort),
|
||||
("testChunkReadingWhereByteCountIsNotAChunkSizeMultiplier", testChunkReadingWhereByteCountIsNotAChunkSizeMultiplier),
|
||||
("testReadMoreThanIntMaxBytesDoesntThrow", testReadMoreThanIntMaxBytesDoesntThrow),
|
||||
("testChunkedReadDoesNotReadShort", testChunkedReadDoesNotReadShort),
|
||||
("testChunkSizeMoreThanTotal", testChunkSizeMoreThanTotal),
|
||||
("testFileRegionReadFromPipeFails", testFileRegionReadFromPipeFails),
|
||||
|
|
|
@ -282,6 +282,16 @@ class NonBlockingFileIOTest: XCTestCase {
|
|||
XCTAssertEqual(2, numCalls)
|
||||
}
|
||||
|
||||
func testReadMoreThanIntMaxBytesDoesntThrow() throws {
|
||||
try XCTSkipIf(MemoryLayout<size_t>.size == MemoryLayout<UInt32>.size)
|
||||
// here we try to read way more data back from the file than it contains but it serves the purpose
|
||||
// even on a small file the OS will return EINVAL if you try to read > INT_MAX bytes
|
||||
try withTemporaryFile(content: "some-dummy-content", { (filehandle, path) -> Void in
|
||||
let content = try self.fileIO.read(fileHandle: filehandle, byteCount:Int(Int32.max)+10, allocator: .init(), eventLoop: self.eventLoop).wait()
|
||||
XCTAssertEqual(String(buffer: content), "some-dummy-content")
|
||||
})
|
||||
}
|
||||
|
||||
func testChunkedReadDoesNotReadShort() throws {
|
||||
var innerError: Error? = nil
|
||||
try withPipe { readFH, writeFH in
|
||||
|
|
Loading…
Reference in New Issue