Files
bun.sh/src/io/MaxBuf.zig
taylor.fish 437e15bae5 Replace catch bun.outOfMemory() with safer alternatives (#22141)
Replace `catch bun.outOfMemory()`, which can accidentally catch
non-OOM-related errors, with either `bun.handleOom` or a manual `catch
|err| switch (err)`.

(For internal tracking: fixes STAB-1070)

---------

Co-authored-by: Dylan Conway <dylan.conway567@gmail.com>
2025-08-26 12:50:25 -07:00

87 lines
2.5 KiB
Zig

const MaxBuf = @This();
// null after subprocess finalize
owned_by_subprocess: ?*Subprocess,
// null after pipereader finalize
owned_by_reader: bool,
// if this goes negative, onMaxBuffer is called on the subprocess
remaining_bytes: i64,
// (once both are null, it is freed)
pub fn createForSubprocess(owner: *Subprocess, ptr: *?*MaxBuf, initial: ?i64) void {
if (initial == null) {
ptr.* = null;
return;
}
const maxbuf = bun.handleOom(bun.default_allocator.create(MaxBuf));
maxbuf.* = .{
.owned_by_subprocess = owner,
.owned_by_reader = false,
.remaining_bytes = initial.?,
};
ptr.* = maxbuf;
}
fn disowned(this: *MaxBuf) bool {
return this.owned_by_subprocess == null and this.owned_by_reader == false;
}
fn destroy(this: *MaxBuf) void {
bun.assert(this.disowned());
bun.default_allocator.destroy(this);
}
pub fn removeFromSubprocess(ptr: *?*MaxBuf) void {
if (ptr.* == null) return;
const this = ptr.*.?;
bun.assert(this.owned_by_subprocess != null);
this.owned_by_subprocess = null;
ptr.* = null;
if (this.disowned()) {
this.destroy();
}
}
pub fn addToPipereader(value: ?*MaxBuf, ptr: *?*MaxBuf) void {
if (value == null) return;
bun.assert(ptr.* == null);
ptr.* = value;
bun.assert(!value.?.owned_by_reader);
value.?.owned_by_reader = true;
}
pub fn removeFromPipereader(ptr: *?*MaxBuf) void {
if (ptr.* == null) return;
const this = ptr.*.?;
bun.assert(this.owned_by_reader);
this.owned_by_reader = false;
ptr.* = null;
if (this.disowned()) {
this.destroy();
}
}
pub fn transferToPipereader(prev: *?*MaxBuf, next: *?*MaxBuf) void {
if (prev.* == null) return;
next.* = prev.*;
prev.* = null;
}
pub fn onReadBytes(this: *MaxBuf, bytes: u64) void {
this.remaining_bytes = std.math.sub(i64, this.remaining_bytes, std.math.cast(i64, bytes) orelse 0) catch -1;
if (this.remaining_bytes < 0 and this.owned_by_subprocess != null) {
const owned_by = this.owned_by_subprocess.?;
if (owned_by.stderr_maxbuf == this) {
MaxBuf.removeFromSubprocess(&owned_by.stderr_maxbuf);
owned_by.onMaxBuffer(.stderr);
} else if (owned_by.stdout_maxbuf == this) {
MaxBuf.removeFromSubprocess(&owned_by.stdout_maxbuf);
owned_by.onMaxBuffer(.stdout);
} else {
bun.assert(false);
}
}
}
pub const Kind = enum {
stdout,
stderr,
};
const bun = @import("bun");
const std = @import("std");
const Subprocess = bun.jsc.Subprocess;