mirror of
https://github.com/SideStore/SideStore.git
synced 2026-02-09 06:43:25 +01:00
- [ConsoleLogger]: Fix writing large data by chunking + stale handle capture
This commit is contained in:
@@ -80,22 +80,55 @@ public class AbstractConsoleLogger<T: OutputStream>: ConsoleLogger{
|
|||||||
let shutdownLock = NSLock()
|
let shutdownLock = NSLock()
|
||||||
|
|
||||||
private func setupReadabilityHandler(for handle: FileHandle?, isError: Bool) {
|
private func setupReadabilityHandler(for handle: FileHandle?, isError: Bool) {
|
||||||
handle?.readabilityHandler = readHandler(for: handle, isError: isError)
|
handle?.readabilityHandler = readHandler(isError: isError)
|
||||||
}
|
}
|
||||||
|
|
||||||
private func readHandler(for handle: FileHandle?, isError: Bool) -> (FileHandle) -> Void {
|
private func readHandler(isError: Bool) -> (FileHandle) -> Void {
|
||||||
return { [weak self] _ in
|
return { [weak self] _ in
|
||||||
guard let self, let data = handle?.availableData else { return }
|
// Lock first before touching anything
|
||||||
|
self?.shutdownLock.lock()
|
||||||
|
defer { self?.shutdownLock.unlock() }
|
||||||
|
|
||||||
shutdownLock.lock()
|
// Capture strong self *after* lock is acquired
|
||||||
defer { shutdownLock.unlock() }
|
guard let self = self else { return }
|
||||||
|
|
||||||
|
let handle = isError ? self.errorHandle : self.outputHandle
|
||||||
|
guard let data = handle?.availableData else { return }
|
||||||
|
|
||||||
writeQueue.async {
|
writeQueue.async {
|
||||||
try? self.writeData(data)
|
try? self.writeData(data)
|
||||||
}
|
}
|
||||||
|
|
||||||
if let fd = isError ? self.originalStderr : self.originalStdout {
|
// 2. Echo to original stdout/stderr if still valid
|
||||||
data.withUnsafeBytes { _ = write(fd, $0.baseAddress, $0.count) }
|
guard let fd = isError ? self.originalStderr : self.originalStdout else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
let appName = Bundle.main.object(forInfoDictionaryKey: "CFBundleName") as? String ?? "UnknownApp"
|
||||||
|
guard fcntl(fd, F_GETFD) != -1 else {
|
||||||
|
NSLog("[%@] ConsoleLogger: Original FD (%d) is invalid, skipping echo", appName, fd)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
data.withUnsafeBytes { rawBufferPointer in
|
||||||
|
guard let base = rawBufferPointer.baseAddress else { return }
|
||||||
|
var remaining = data.count
|
||||||
|
var offset = 0
|
||||||
|
let maxChunkSize = 16 * 1024 // 16 KB chunks
|
||||||
|
|
||||||
|
// write in chunks, else will throw 'Result too large'
|
||||||
|
while remaining > 0 {
|
||||||
|
let chunkSize = min(maxChunkSize, remaining)
|
||||||
|
let written = write(fd, base.advanced(by: offset), chunkSize)
|
||||||
|
|
||||||
|
if written < 0 {
|
||||||
|
NSLog("[%@] ConsoleLogger: Failed to re-echo to FD %d: %s", appName, fd, strerror(errno))
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
remaining -= written
|
||||||
|
offset += written
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user