Skip to content

Commit 5e709b3

Browse files
committed
[Backtracing][Linux] Work correctly in the presence of partial reads.
There's a chance that pipes might perform a partial read; we should handle that case. rdar://110261712
1 parent 6ad9720 commit 5e709b3

File tree

1 file changed

+51
-12
lines changed

1 file changed

+51
-12
lines changed

stdlib/public/Backtracing/MemoryReader.swift

Lines changed: 51 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -162,30 +162,69 @@ extension MemoryReader {
162162
self.fd = fd
163163
}
164164

165+
private func safeRead(_ fd: CInt, _ buffer: UnsafeMutableRawBufferPointer) throws -> Int {
166+
var done = 0
167+
while done < buffer.count {
168+
var ret: ssize_t = 0
169+
repeat {
170+
ret = read(fd, buffer.baseAddress! + done, buffer.count - done)
171+
} while ret < 0 && _swift_get_errno() == EINTR
172+
if ret < 0 {
173+
throw POSIXError(errno: _swift_get_errno())
174+
}
175+
if ret == 0 {
176+
break
177+
}
178+
done += Int(ret)
179+
}
180+
181+
return done
182+
}
183+
184+
private func safeWrite(_ fd: CInt, _ buffer: UnsafeRawBufferPointer) throws -> Int {
185+
var done = 0
186+
while done < buffer.count {
187+
var ret: ssize_t = 0
188+
repeat {
189+
ret = write(fd, buffer.baseAddress! + done, buffer.count - done)
190+
} while ret < 0 && _swift_get_errno() == EINTR
191+
if ret < 0 {
192+
throw POSIXError(errno: _swift_get_errno())
193+
}
194+
if ret == 0 {
195+
break
196+
}
197+
done += Int(ret)
198+
}
199+
200+
return done
201+
}
202+
165203
private func sendRequest(for bytes: Size, from addr: Address) throws {
166204
var request = memserver_req(addr: addr, len: bytes)
167205
try withUnsafeBytes(of: &request){ ptr in
168-
let ret = write(fd, ptr.baseAddress, ptr.count)
169-
if ret < 0 || ret != ptr.count {
170-
throw POSIXError(errno: _swift_get_errno())
206+
let ret = safeWrite(fd, ptr)
207+
if ret != ptr.count {
208+
throw MemserverError(message: "Channel closed prematurely")
171209
}
172210
}
173211
}
174212

175213
private func receiveReply() throws -> memserver_resp {
176214
var response = memserver_resp(addr: 0, len: 0)
177215
try withUnsafeMutableBytes(of: &response){ ptr in
178-
let ret = read(fd, ptr.baseAddress, ptr.count)
179-
if ret < 0 || ret != ptr.count {
180-
throw POSIXError(errno: _swift_get_errno())
216+
let ret = safeRead(fd, ptr)
217+
if ret != ptr.count {
218+
throw MemserverError(message: "Channel closed prematurely")
181219
}
182220
}
183221
return response
184222
}
185223

186224
public func fetch<T>(from addr: Address,
187225
into buffer: UnsafeMutableBufferPointer<T>) throws {
188-
try buffer.withMemoryRebound(to: UInt8.self) { bytes in
226+
try buffer.withMemoryRebound(to: UInt8.self) {
227+
let bytes = UnsafeMutableRawBufferPointer($0)
189228
try sendRequest(for: Size(bytes.count), from: addr)
190229

191230
var done = 0
@@ -200,12 +239,12 @@ extension MemoryReader {
200239
throw MemserverError(message: "Overrun at \(hex(addr)) trying to read \(bytes.count) bytes")
201240
}
202241

203-
let ret = read(fd,
204-
bytes.baseAddress!.advanced(by: done),
205-
Int(reply.len))
242+
let ret = try safeRead(fd,
243+
UnsafeMutableRawBufferPointer(
244+
rebasing: bytes[done..<done+Int(reply.len)]))
206245

207-
if ret < 0 || ret != reply.len {
208-
throw POSIXError(errno: _swift_get_errno())
246+
if ret != reply.len {
247+
throw MemserverError(message: "Channel closed prematurely")
209248
}
210249

211250
done += Int(reply.len)

0 commit comments

Comments
 (0)