Compare commits

...

4 Commits

Author SHA1 Message Date
Claude Bot
60af3b39f9 ci: retry build (transient GitHub CDN download failure on mimalloc)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-01 10:57:00 +00:00
Claude Bot
18766c0547 fix(windows): set system_error in all OOM catch blocks so finalize() reports failure
finalize() only checks this.system_error to decide error vs success.
Four OOM catch blocks only set this.errno, causing finalize() to
report success with invalid data on allocation failure. Now all catch
blocks set both this.errno and this.system_error, matching the existing
pattern at line 688-689.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-01 10:54:05 +00:00
Claude Bot
e5643d4e42 ci: retry build (previous failure was transient GitHub download error)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-01 10:49:23 +00:00
Claude Bot
b1f75e0a71 fix(windows): fix fd leak and use-after-free in ReadFileUV error paths
Two bugs in ReadFileUV error handling:

1. onRead() error path called finalize() directly instead of onFinish(),
   bypassing doClose() and leaking the open file descriptor.

2. queueRead() OOM catch block for non-regular files called onFinish()
   but was missing a return, causing fall-through to remainingBuffer()
   on freed memory (use-after-free).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-01 10:46:38 +00:00

View File

@@ -691,8 +691,9 @@ pub const ReadFileUV = struct {
return;
}
// add an extra 16 bytes to the buffer to avoid having to resize it for trailing extra data
this.buffer.ensureTotalCapacityPrecise(this.byte_store.allocator, @min(this.size + 16, @as(usize, std.math.maxInt(bun.windows.ULONG)))) catch |err| {
this.errno = err;
this.buffer.ensureTotalCapacityPrecise(this.byte_store.allocator, @min(this.size + 16, @as(usize, std.math.maxInt(bun.windows.ULONG)))) catch {
this.errno = error.OutOfMemory;
this.system_error = bun.sys.Error.fromCode(bun.sys.E.NOMEM, .read).toSystemError();
this.onFinish();
return;
};
@@ -719,9 +720,11 @@ pub const ReadFileUV = struct {
// non-regular files have variable sizes, so we always ensure
// theres at least 4096 bytes of free space. there has already
// been an initial allocation done for us
this.buffer.ensureUnusedCapacity(this.byte_store.allocator, 4096) catch |err| {
this.errno = err;
this.buffer.ensureUnusedCapacity(this.byte_store.allocator, 4096) catch {
this.errno = error.OutOfMemory;
this.system_error = bun.sys.Error.fromCode(bun.sys.E.NOMEM, .read).toSystemError();
this.onFinish();
return;
};
}
@@ -750,8 +753,9 @@ pub const ReadFileUV = struct {
// We are done reading.
this.byte_store = ByteStore.init(
this.buffer.toOwnedSlice(this.byte_store.allocator) catch |err| {
this.errno = err;
this.buffer.toOwnedSlice(this.byte_store.allocator) catch {
this.errno = error.OutOfMemory;
this.system_error = bun.sys.Error.fromCode(bun.sys.E.NOMEM, .read).toSystemError();
this.onFinish();
return;
},
@@ -769,15 +773,16 @@ pub const ReadFileUV = struct {
if (result.errEnum()) |errno| {
this.errno = bun.errnoToZigErr(errno);
this.system_error = bun.sys.Error.fromCode(errno, .read).toSystemError();
this.finalize();
this.onFinish();
return;
}
if (result.int() == 0) {
// We are done reading.
this.byte_store = ByteStore.init(
this.buffer.toOwnedSlice(this.byte_store.allocator) catch |err| {
this.errno = err;
this.buffer.toOwnedSlice(this.byte_store.allocator) catch {
this.errno = error.OutOfMemory;
this.system_error = bun.sys.Error.fromCode(bun.sys.E.NOMEM, .read).toSystemError();
this.onFinish();
return;
},