mirror of
https://github.com/oven-sh/bun
synced 2026-02-11 19:38:58 +00:00
fix again and add reproduction test
This commit is contained in:
@@ -703,18 +703,6 @@ pub const Subprocess = struct {
|
||||
return .undefined;
|
||||
}
|
||||
|
||||
pub fn onStdinDestroyed(this: *Subprocess) void {
|
||||
this.island.clearStdin();
|
||||
|
||||
if (this.island.subprocess == null) {
|
||||
// if the process has already been garbage collected, we can free the memory now
|
||||
bun.default_allocator.destroy(this);
|
||||
} else {
|
||||
// otherwise update the pending activity flag
|
||||
this.updateHasPendingActivity();
|
||||
}
|
||||
}
|
||||
|
||||
pub fn doSend(this: *Subprocess, global: *JSC.JSGlobalObject, callFrame: *JSC.CallFrame) JSValue {
|
||||
const ipc_data = &(this.ipc_data orelse {
|
||||
if (this.hasExited()) {
|
||||
@@ -1180,13 +1168,6 @@ pub const Subprocess = struct {
|
||||
// When the stream has closed we need to be notified to prevent a use-after-free
|
||||
// We can test for this use-after-free by enabling hot module reloading on a file and then saving it twice
|
||||
pub fn onClose(this: *Writable, _: ?bun.sys.Error) void {
|
||||
const process: *Subprocess = @fieldParentPtr("stdin", this);
|
||||
|
||||
if (process.this_jsvalue != .zero) {
|
||||
if (Subprocess.stdinGetCached(process.this_jsvalue)) |existing_value| {
|
||||
JSC.WebCore.FileSink.JSSink.setDestroyCallback(existing_value, 0);
|
||||
}
|
||||
}
|
||||
|
||||
switch (this.*) {
|
||||
.buffer => {
|
||||
@@ -1194,11 +1175,11 @@ pub const Subprocess = struct {
|
||||
},
|
||||
.pipe => {
|
||||
this.pipe.deref();
|
||||
this.pipe.island.?.clearStdin();
|
||||
},
|
||||
else => {},
|
||||
}
|
||||
|
||||
process.onStdinDestroyed();
|
||||
|
||||
this.* = .{
|
||||
.ignore = {},
|
||||
@@ -1230,6 +1211,7 @@ pub const Subprocess = struct {
|
||||
},
|
||||
}
|
||||
pipe.writer.setParent(pipe);
|
||||
pipe.island = island;
|
||||
island.stdin = pipe;
|
||||
|
||||
return Writable{
|
||||
@@ -1342,7 +1324,6 @@ pub const Subprocess = struct {
|
||||
}
|
||||
return pipe.toJSWithDestructor(
|
||||
globalThis,
|
||||
JSC.WebCore.SinkDestructor.Ptr.init(subprocess.island),
|
||||
);
|
||||
}
|
||||
},
|
||||
@@ -1350,13 +1331,6 @@ pub const Subprocess = struct {
|
||||
}
|
||||
|
||||
pub fn finalize(this: *Writable) void {
|
||||
const subprocess: *Subprocess = @fieldParentPtr("stdin", this);
|
||||
if (subprocess.this_jsvalue != .zero) {
|
||||
if (JSC.Codegen.JSSubprocess.stdinGetCached(subprocess.this_jsvalue)) |existing_value| {
|
||||
JSC.WebCore.FileSink.JSSink.setDestroyCallback(existing_value, 0);
|
||||
}
|
||||
}
|
||||
|
||||
return switch (this.*) {
|
||||
.pipe => |pipe| {
|
||||
if (pipe.signal.ptr == @as(*anyopaque, @ptrCast(this))) {
|
||||
@@ -1424,13 +1398,9 @@ pub const Subprocess = struct {
|
||||
this.stdin.buffer.close();
|
||||
}
|
||||
|
||||
if (existing_stdin_value != .zero) {
|
||||
JSC.WebCore.FileSink.JSSink.setDestroyCallback(existing_stdin_value, 0);
|
||||
}
|
||||
|
||||
if (stdin) |pipe| {
|
||||
_ = pipe;
|
||||
this.island.clearStdin();
|
||||
pipe.onAttachedProcessExit();
|
||||
}
|
||||
|
||||
var did_update_has_pending_activity = false;
|
||||
@@ -1559,10 +1529,7 @@ pub const Subprocess = struct {
|
||||
this.process.deref();
|
||||
|
||||
this.island.clearSubprocess();
|
||||
if (this.island.stdin == null) {
|
||||
// if no file sink exists we can free immediately
|
||||
bun.default_allocator.destroy(this);
|
||||
}
|
||||
bun.default_allocator.destroy(this);
|
||||
}
|
||||
|
||||
pub fn getExited(
|
||||
@@ -2293,13 +2260,6 @@ pub const Subprocess = struct {
|
||||
subprocess: ?*Subprocess = null,
|
||||
stdin: ?*JSC.WebCore.FileSink = null,
|
||||
|
||||
pub fn onStdinDestroyed(this: *Island) void {
|
||||
const had_subprocess = this.subprocess != null;
|
||||
this.clearStdin();
|
||||
if (!had_subprocess) return; // dont uaf the next line
|
||||
this.subprocess.?.onStdinDestroyed();
|
||||
}
|
||||
|
||||
pub fn clearSubprocess(this: *Island) void {
|
||||
this.subprocess = null;
|
||||
if (this.stdin == null) this.destroy();
|
||||
|
||||
10
src/bun.js/bindings/headers.h
generated
10
src/bun.js/bindings/headers.h
generated
@@ -596,7 +596,7 @@ extern "C" JSC__JSValue SYSV_ABI Bun__Path__toNamespacedPath(JSC__JSGlobalObject
|
||||
#endif
|
||||
|
||||
CPP_DECL JSC__JSValue ArrayBufferSink__assignToStream(JSC__JSGlobalObject* arg0, JSC__JSValue JSValue1, void* arg2, void** arg3);
|
||||
CPP_DECL JSC__JSValue ArrayBufferSink__createObject(JSC__JSGlobalObject* arg0, void* arg1, uintptr_t destructor);
|
||||
CPP_DECL JSC__JSValue ArrayBufferSink__createObject(JSC__JSGlobalObject* arg0, void* arg1);
|
||||
CPP_DECL void ArrayBufferSink__detachPtr(JSC__JSValue JSValue0);
|
||||
CPP_DECL void* ArrayBufferSink__fromJS(JSC__JSGlobalObject* arg0, JSC__JSValue JSValue1);
|
||||
CPP_DECL void ArrayBufferSink__onClose(JSC__JSValue JSValue0, JSC__JSValue JSValue1);
|
||||
@@ -616,7 +616,7 @@ BUN_DECLARE_HOST_FUNCTION(ArrayBufferSink__write);
|
||||
|
||||
#endif
|
||||
CPP_DECL JSC__JSValue HTTPSResponseSink__assignToStream(JSC__JSGlobalObject* arg0, JSC__JSValue JSValue1, void* arg2, void** arg3);
|
||||
CPP_DECL JSC__JSValue HTTPSResponseSink__createObject(JSC__JSGlobalObject* arg0, void* arg1, uintptr_t destructor);
|
||||
CPP_DECL JSC__JSValue HTTPSResponseSink__createObject(JSC__JSGlobalObject* arg0, void* arg1);
|
||||
CPP_DECL void HTTPSResponseSink__detachPtr(JSC__JSValue JSValue0);
|
||||
CPP_DECL void* HTTPSResponseSink__fromJS(JSC__JSGlobalObject* arg0, JSC__JSValue JSValue1);
|
||||
CPP_DECL void HTTPSResponseSink__onClose(JSC__JSValue JSValue0, JSC__JSValue JSValue1);
|
||||
@@ -636,7 +636,7 @@ BUN_DECLARE_HOST_FUNCTION(HTTPSResponseSink__write);
|
||||
|
||||
#endif
|
||||
CPP_DECL JSC__JSValue HTTPResponseSink__assignToStream(JSC__JSGlobalObject* arg0, JSC__JSValue JSValue1, void* arg2, void** arg3);
|
||||
CPP_DECL JSC__JSValue HTTPResponseSink__createObject(JSC__JSGlobalObject* arg0, void* arg1, uintptr_t destructor);
|
||||
CPP_DECL JSC__JSValue HTTPResponseSink__createObject(JSC__JSGlobalObject* arg0, void* arg1);
|
||||
CPP_DECL void HTTPResponseSink__detachPtr(JSC__JSValue JSValue0);
|
||||
CPP_DECL void* HTTPResponseSink__fromJS(JSC__JSGlobalObject* arg0, JSC__JSValue JSValue1);
|
||||
CPP_DECL void HTTPResponseSink__onClose(JSC__JSValue JSValue0, JSC__JSValue JSValue1);
|
||||
@@ -656,7 +656,7 @@ BUN_DECLARE_HOST_FUNCTION(HTTPResponseSink__write);
|
||||
|
||||
#endif
|
||||
CPP_DECL JSC__JSValue FileSink__assignToStream(JSC__JSGlobalObject* arg0, JSC__JSValue JSValue1, void* arg2, void** arg3);
|
||||
CPP_DECL JSC__JSValue FileSink__createObject(JSC__JSGlobalObject* arg0, void* arg1, uintptr_t destructor);
|
||||
CPP_DECL JSC__JSValue FileSink__createObject(JSC__JSGlobalObject* arg0, void* arg1);
|
||||
CPP_DECL void FileSink__detachPtr(JSC__JSValue JSValue0);
|
||||
CPP_DECL void* FileSink__fromJS(JSC__JSGlobalObject* arg0, JSC__JSValue JSValue1);
|
||||
CPP_DECL void FileSink__onClose(JSC__JSValue JSValue0, JSC__JSValue JSValue1);
|
||||
@@ -677,7 +677,7 @@ BUN_DECLARE_HOST_FUNCTION(FileSink__write);
|
||||
#endif
|
||||
|
||||
CPP_DECL JSC__JSValue FileSink__assignToStream(JSC__JSGlobalObject* arg0, JSC__JSValue JSValue1, void* arg2, void** arg3);
|
||||
CPP_DECL JSC__JSValue FileSink__createObject(JSC__JSGlobalObject* arg0, void* arg1, uintptr_t destructor);
|
||||
CPP_DECL JSC__JSValue FileSink__createObject(JSC__JSGlobalObject* arg0, void* arg1);
|
||||
CPP_DECL void FileSink__detachPtr(JSC__JSValue JSValue0);
|
||||
CPP_DECL void* FileSink__fromJS(JSC__JSGlobalObject* arg0, JSC__JSValue JSValue1);
|
||||
CPP_DECL void FileSink__onClose(JSC__JSValue JSValue0, JSC__JSValue JSValue1);
|
||||
|
||||
12
src/bun.js/bindings/headers.zig
generated
12
src/bun.js/bindings/headers.zig
generated
@@ -357,30 +357,26 @@ pub extern fn Zig__GlobalObject__create(arg0: ?*anyopaque, arg1: i32, arg2: bool
|
||||
pub extern fn Zig__GlobalObject__getModuleRegistryMap(arg0: *bindings.JSGlobalObject) ?*anyopaque;
|
||||
pub extern fn Zig__GlobalObject__resetModuleRegistryMap(arg0: *bindings.JSGlobalObject, arg1: ?*anyopaque) bool;
|
||||
pub extern fn ArrayBufferSink__assignToStream(arg0: *bindings.JSGlobalObject, JSValue1: JSC__JSValue, arg2: ?*anyopaque, arg3: [*c]*anyopaque) JSC__JSValue;
|
||||
pub extern fn ArrayBufferSink__createObject(arg0: *bindings.JSGlobalObject, arg1: ?*anyopaque, onDestroyPtrTag: usize) JSC__JSValue;
|
||||
pub extern fn ArrayBufferSink__createObject(arg0: *bindings.JSGlobalObject, arg1: ?*anyopaque) JSC__JSValue;
|
||||
pub extern fn ArrayBufferSink__detachPtr(JSValue0: JSC__JSValue) void;
|
||||
pub extern fn ArrayBufferSink__setDestroyCallback(JSValue0: JSC__JSValue, callback: usize) void;
|
||||
pub extern fn ArrayBufferSink__fromJS(arg0: *bindings.JSGlobalObject, JSValue1: JSC__JSValue) ?*anyopaque;
|
||||
pub extern fn ArrayBufferSink__onClose(JSValue0: JSC__JSValue, JSValue1: JSC__JSValue) void;
|
||||
pub extern fn ArrayBufferSink__onReady(JSValue0: JSC__JSValue, JSValue1: JSC__JSValue, JSValue2: JSC__JSValue) void;
|
||||
pub extern fn HTTPSResponseSink__assignToStream(arg0: *bindings.JSGlobalObject, JSValue1: JSC__JSValue, arg2: ?*anyopaque, arg3: [*c]*anyopaque) JSC__JSValue;
|
||||
pub extern fn HTTPSResponseSink__createObject(arg0: *bindings.JSGlobalObject, arg1: ?*anyopaque, onDestroyPtrTag: usize) JSC__JSValue;
|
||||
pub extern fn HTTPSResponseSink__createObject(arg0: *bindings.JSGlobalObject, arg1: ?*anyopaque) JSC__JSValue;
|
||||
pub extern fn HTTPSResponseSink__detachPtr(JSValue0: JSC__JSValue) void;
|
||||
pub extern fn HTTPSResponseSink__setDestroyCallback(JSValue0: JSC__JSValue, callback: usize) void;
|
||||
pub extern fn HTTPSResponseSink__fromJS(arg0: *bindings.JSGlobalObject, JSValue1: JSC__JSValue) ?*anyopaque;
|
||||
pub extern fn HTTPSResponseSink__onClose(JSValue0: JSC__JSValue, JSValue1: JSC__JSValue) void;
|
||||
pub extern fn HTTPSResponseSink__onReady(JSValue0: JSC__JSValue, JSValue1: JSC__JSValue, JSValue2: JSC__JSValue) void;
|
||||
pub extern fn HTTPResponseSink__assignToStream(arg0: *bindings.JSGlobalObject, JSValue1: JSC__JSValue, arg2: ?*anyopaque, arg3: [*c]*anyopaque) JSC__JSValue;
|
||||
pub extern fn HTTPResponseSink__createObject(arg0: *bindings.JSGlobalObject, arg1: ?*anyopaque, onDestroyPtrTag: usize) JSC__JSValue;
|
||||
pub extern fn HTTPResponseSink__createObject(arg0: *bindings.JSGlobalObject, arg1: ?*anyopaque) JSC__JSValue;
|
||||
pub extern fn HTTPResponseSink__detachPtr(JSValue0: JSC__JSValue) void;
|
||||
pub extern fn HTTPResponseSink__setDestroyCallback(JSValue0: JSC__JSValue, callback: usize) void;
|
||||
pub extern fn HTTPResponseSink__fromJS(arg0: *bindings.JSGlobalObject, JSValue1: JSC__JSValue) ?*anyopaque;
|
||||
pub extern fn HTTPResponseSink__onClose(JSValue0: JSC__JSValue, JSValue1: JSC__JSValue) void;
|
||||
pub extern fn HTTPResponseSink__onReady(JSValue0: JSC__JSValue, JSValue1: JSC__JSValue, JSValue2: JSC__JSValue) void;
|
||||
pub extern fn FileSink__assignToStream(arg0: *bindings.JSGlobalObject, JSValue1: JSC__JSValue, arg2: ?*anyopaque, arg3: [*c]*anyopaque) JSC__JSValue;
|
||||
pub extern fn FileSink__createObject(arg0: *bindings.JSGlobalObject, arg1: ?*anyopaque, onDestroyPtrTag: usize) JSC__JSValue;
|
||||
pub extern fn FileSink__createObject(arg0: *bindings.JSGlobalObject, arg1: ?*anyopaque) JSC__JSValue;
|
||||
pub extern fn FileSink__detachPtr(JSValue0: JSC__JSValue) void;
|
||||
pub extern fn FileSink__setDestroyCallback(JSValue0: JSC__JSValue, callback: usize) void;
|
||||
pub extern fn FileSink__fromJS(arg0: *bindings.JSGlobalObject, JSValue1: JSC__JSValue) ?*anyopaque;
|
||||
pub extern fn FileSink__onClose(JSValue0: JSC__JSValue, JSValue1: JSC__JSValue) void;
|
||||
pub extern fn FileSink__onReady(JSValue0: JSC__JSValue, JSValue1: JSC__JSValue, JSValue2: JSC__JSValue) void;
|
||||
|
||||
@@ -1528,40 +1528,6 @@ const AutoFlusher = struct {
|
||||
}
|
||||
};
|
||||
|
||||
pub const SinkDestructor = struct {
|
||||
const Detached = opaque {};
|
||||
const Subprocess = JSC.API.Bun.Subprocess;
|
||||
pub const Ptr = bun.TaggedPointerUnion(.{
|
||||
Detached,
|
||||
Subprocess.Island,
|
||||
});
|
||||
|
||||
pub export fn Bun__onSinkDestroyed(
|
||||
ptr_value: ?*anyopaque,
|
||||
sink_ptr: ?*anyopaque,
|
||||
) callconv(.C) void {
|
||||
_ = sink_ptr; // autofix
|
||||
const ptr = Ptr.from(ptr_value);
|
||||
|
||||
if (ptr.isNull()) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (ptr.tag()) {
|
||||
.Detached => {
|
||||
return;
|
||||
},
|
||||
.Island => {
|
||||
const island = ptr.as(Subprocess.Island);
|
||||
island.onStdinDestroyed();
|
||||
},
|
||||
else => {
|
||||
Output.debugWarn("Unknown sink type", .{});
|
||||
},
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
pub fn NewJSSink(comptime SinkType: type, comptime name_: []const u8) type {
|
||||
return struct {
|
||||
sink: SinkType,
|
||||
@@ -1610,10 +1576,10 @@ pub fn NewJSSink(comptime SinkType: type, comptime name_: []const u8) type {
|
||||
return shim.cppFn("onStart", .{ ptr, globalThis });
|
||||
}
|
||||
|
||||
pub fn createObject(globalThis: *JSGlobalObject, object: *anyopaque, destructor: usize) callconv(.C) JSValue {
|
||||
pub fn createObject(globalThis: *JSGlobalObject, object: *anyopaque) callconv(.C) JSValue {
|
||||
JSC.markBinding(@src());
|
||||
|
||||
return shim.cppFn("createObject", .{ globalThis, object, destructor });
|
||||
return shim.cppFn("createObject", .{ globalThis, object });
|
||||
}
|
||||
|
||||
pub fn fromJS(globalThis: *JSGlobalObject, value: JSValue) ?*anyopaque {
|
||||
@@ -1622,12 +1588,6 @@ pub fn NewJSSink(comptime SinkType: type, comptime name_: []const u8) type {
|
||||
return shim.cppFn("fromJS", .{ globalThis, value });
|
||||
}
|
||||
|
||||
pub fn setDestroyCallback(value: JSValue, callback: usize) void {
|
||||
JSC.markBinding(@src());
|
||||
|
||||
return shim.cppFn("setDestroyCallback", .{ value, callback });
|
||||
}
|
||||
|
||||
pub fn construct(globalThis: *JSGlobalObject, _: *JSC.CallFrame) callconv(JSC.conv) JSValue {
|
||||
JSC.markBinding(@src());
|
||||
|
||||
@@ -1651,7 +1611,7 @@ pub fn NewJSSink(comptime SinkType: type, comptime name_: []const u8) type {
|
||||
return .undefined;
|
||||
};
|
||||
this.sink.construct(allocator);
|
||||
return createObject(globalThis, this, 0);
|
||||
return createObject(globalThis, this);
|
||||
}
|
||||
|
||||
pub fn finalize(ptr: *anyopaque) callconv(.C) void {
|
||||
@@ -2954,6 +2914,7 @@ pub const FileSink = struct {
|
||||
is_socket: bool = false,
|
||||
fd: bun.FileDescriptor = bun.invalid_fd,
|
||||
has_js_called_unref: bool = false,
|
||||
island: ?*JSC.Subprocess.Island = null,
|
||||
|
||||
const log = Output.scoped(.FileSink, false);
|
||||
|
||||
@@ -3367,11 +3328,11 @@ pub const FileSink = struct {
|
||||
}
|
||||
|
||||
pub fn toJS(this: *FileSink, globalThis: *JSGlobalObject) JSValue {
|
||||
return JSSink.createObject(globalThis, this, 0);
|
||||
return JSSink.createObject(globalThis, this);
|
||||
}
|
||||
|
||||
pub fn toJSWithDestructor(this: *FileSink, globalThis: *JSGlobalObject, destructor: ?SinkDestructor.Ptr) JSValue {
|
||||
return JSSink.createObject(globalThis, this, if (destructor) |dest| @intFromPtr(dest.ptr()) else 0);
|
||||
pub fn toJSWithDestructor(this: *FileSink, globalThis: *JSGlobalObject) JSValue {
|
||||
return JSSink.createObject(globalThis, this);
|
||||
}
|
||||
|
||||
pub fn endFromJS(this: *FileSink, globalThis: *JSGlobalObject) JSC.Maybe(JSValue) {
|
||||
|
||||
@@ -64,7 +64,7 @@ function header() {
|
||||
class ${className} final : public JSC::JSDestructibleObject {
|
||||
public:
|
||||
using Base = JSC::JSDestructibleObject;
|
||||
static ${className}* create(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::Structure* structure, void* sinkPtr, uintptr_t destructor = 0);
|
||||
static ${className}* create(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::Structure* structure, void* sinkPtr);
|
||||
static constexpr SinkID Sink = SinkID::${name};
|
||||
|
||||
DECLARE_EXPORT_INFO;
|
||||
@@ -106,13 +106,11 @@ function header() {
|
||||
void* m_sinkPtr;
|
||||
int m_refCount { 1 };
|
||||
|
||||
uintptr_t m_onDestroy { 0 };
|
||||
|
||||
${className}(JSC::VM& vm, JSC::Structure* structure, void* sinkPtr, uintptr_t onDestroy)
|
||||
${className}(JSC::VM& vm, JSC::Structure* structure, void* sinkPtr)
|
||||
: Base(vm, structure)
|
||||
{
|
||||
m_sinkPtr = sinkPtr;
|
||||
m_onDestroy = onDestroy;
|
||||
}
|
||||
|
||||
void finishCreation(JSC::VM&);
|
||||
@@ -123,7 +121,7 @@ function header() {
|
||||
class ${controller} final : public JSC::JSDestructibleObject {
|
||||
public:
|
||||
using Base = JSC::JSDestructibleObject;
|
||||
static ${controller}* create(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::Structure* structure, void* sinkPtr, uintptr_t onDestroy);
|
||||
static ${controller}* create(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::Structure* structure, void* sinkPtr);
|
||||
static constexpr SinkID Sink = SinkID::${name};
|
||||
|
||||
DECLARE_EXPORT_INFO;
|
||||
@@ -162,13 +160,10 @@ function header() {
|
||||
mutable WriteBarrier<JSC::Unknown> m_onClose;
|
||||
mutable JSC::Weak<JSObject> m_weakReadableStream;
|
||||
|
||||
uintptr_t m_onDestroy { 0 };
|
||||
|
||||
${controller}(JSC::VM& vm, JSC::Structure* structure, void* sinkPtr, uintptr_t onDestroy)
|
||||
${controller}(JSC::VM& vm, JSC::Structure* structure, void* sinkPtr)
|
||||
: Base(vm, structure)
|
||||
{
|
||||
m_sinkPtr = sinkPtr;
|
||||
m_onDestroy = onDestroy;
|
||||
}
|
||||
|
||||
void finishCreation(JSC::VM&);
|
||||
@@ -566,10 +561,6 @@ const ClassInfo ${controller}::s_info = { "${controllerName}"_s, &Base::s_info,
|
||||
|
||||
${className}::~${className}()
|
||||
{
|
||||
if (m_onDestroy) {
|
||||
Bun__onSinkDestroyed(m_onDestroy, m_sinkPtr);
|
||||
}
|
||||
|
||||
if (m_sinkPtr) {
|
||||
${name}__finalize(m_sinkPtr);
|
||||
}
|
||||
@@ -578,10 +569,6 @@ ${className}::~${className}()
|
||||
|
||||
${controller}::~${controller}()
|
||||
{
|
||||
if (m_onDestroy) {
|
||||
Bun__onSinkDestroyed(m_onDestroy, m_sinkPtr);
|
||||
}
|
||||
|
||||
if (m_sinkPtr) {
|
||||
${name}__finalize(m_sinkPtr);
|
||||
}
|
||||
@@ -598,12 +585,6 @@ JSObject* JS${controllerName}::createPrototype(VM& vm, JSDOMGlobalObject& global
|
||||
}
|
||||
|
||||
void JS${controllerName}::detach() {
|
||||
if (m_onDestroy) {
|
||||
auto destroy = m_onDestroy;
|
||||
m_onDestroy = 0;
|
||||
Bun__onSinkDestroyed(destroy, m_sinkPtr);
|
||||
}
|
||||
|
||||
m_sinkPtr = nullptr;
|
||||
m_onPull.clear();
|
||||
|
||||
@@ -635,16 +616,16 @@ ${constructor}* ${constructor}::create(JSC::VM& vm, JSC::JSGlobalObject* globalO
|
||||
return ptr;
|
||||
}
|
||||
|
||||
${className}* ${className}::create(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::Structure* structure, void* sinkPtr, uintptr_t onDestroy)
|
||||
${className}* ${className}::create(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::Structure* structure, void* sinkPtr)
|
||||
{
|
||||
${className}* ptr = new (NotNull, JSC::allocateCell<${className}>(vm)) ${className}(vm, structure, sinkPtr, onDestroy);
|
||||
${className}* ptr = new (NotNull, JSC::allocateCell<${className}>(vm)) ${className}(vm, structure, sinkPtr);
|
||||
ptr->finishCreation(vm);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
${controller}* ${controller}::create(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::Structure* structure, void* sinkPtr, uintptr_t onDestroy)
|
||||
${controller}* ${controller}::create(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::Structure* structure, void* sinkPtr)
|
||||
{
|
||||
${controller}* ptr = new (NotNull, JSC::allocateCell<${controller}>(vm)) ${controller}(vm, structure, sinkPtr, onDestroy);
|
||||
${controller}* ptr = new (NotNull, JSC::allocateCell<${controller}>(vm)) ${controller}(vm, structure, sinkPtr);
|
||||
ptr->finishCreation(vm);
|
||||
return ptr;
|
||||
}
|
||||
@@ -697,16 +678,6 @@ void ${controller}::finishCreation(VM& vm)
|
||||
ASSERT(inherits(info()));
|
||||
}
|
||||
|
||||
extern "C" void ${name}__setDestroyCallback(EncodedJSValue encodedValue, uintptr_t callback)
|
||||
{
|
||||
JSValue value = JSValue::decode(encodedValue);
|
||||
if (auto* sink = JSC::jsDynamicCast<WebCore::${className}*>(value)) {
|
||||
sink->m_onDestroy = callback;
|
||||
} else if (auto* controller = JSC::jsDynamicCast<WebCore::${controller}*>(value)) {
|
||||
controller->m_onDestroy = callback;
|
||||
}
|
||||
}
|
||||
|
||||
void ${className}::analyzeHeap(JSCell* cell, HeapAnalyzer& analyzer)
|
||||
{
|
||||
auto* thisObject = jsCast<${className}*>(cell);
|
||||
@@ -844,12 +815,12 @@ default:
|
||||
const { className, controller, prototypeName, controllerPrototypeName, constructor } = names(name);
|
||||
|
||||
templ += `
|
||||
extern "C" JSC__JSValue ${name}__createObject(JSC__JSGlobalObject* arg0, void* sinkPtr, uintptr_t destructor)
|
||||
extern "C" JSC__JSValue ${name}__createObject(JSC__JSGlobalObject* arg0, void* sinkPtr)
|
||||
{
|
||||
auto& vm = arg0->vm();
|
||||
Zig::GlobalObject* globalObject = reinterpret_cast<Zig::GlobalObject*>(arg0);
|
||||
JSC::Structure* structure = globalObject->${name}Structure();
|
||||
return JSC::JSValue::encode(WebCore::JS${name}::create(vm, globalObject, structure, sinkPtr, destructor));
|
||||
return JSC::JSValue::encode(WebCore::JS${name}::create(vm, globalObject, structure, sinkPtr));
|
||||
}
|
||||
|
||||
extern "C" void* ${name}__fromJS(JSC__JSGlobalObject* arg0, JSC__JSValue JSValue1)
|
||||
@@ -883,7 +854,7 @@ extern "C" JSC__JSValue ${name}__assignToStream(JSC__JSGlobalObject* arg0, JSC__
|
||||
Zig::GlobalObject* globalObject = reinterpret_cast<Zig::GlobalObject*>(arg0);
|
||||
|
||||
JSC::Structure* structure = WebCore::getDOMStructure<WebCore::${controller}>(vm, *globalObject);
|
||||
WebCore::${controller} *controller = WebCore::${controller}::create(vm, globalObject, structure, sinkPtr, 0);
|
||||
WebCore::${controller} *controller = WebCore::${controller}::create(vm, globalObject, structure, sinkPtr);
|
||||
*controllerValue = reinterpret_cast<void*>(JSC::JSValue::encode(controller));
|
||||
return globalObject->assignToStream(JSC::JSValue::decode(stream), controller);
|
||||
}
|
||||
|
||||
@@ -246,36 +246,7 @@ pub const ShellSubprocess = struct {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn toJS(this: *Writable, globalThis: *JSC.JSGlobalObject, subprocess: *Subprocess) JSValue {
|
||||
return switch (this.*) {
|
||||
.fd => |fd| JSValue.jsNumber(fd),
|
||||
.memfd, .ignore => JSValue.jsUndefined(),
|
||||
.buffer, .inherit => JSValue.jsUndefined(),
|
||||
.pipe => |pipe| {
|
||||
this.* = .{ .ignore = {} };
|
||||
if (subprocess.process.hasExited() and !subprocess.flags.has_stdin_destructor_called) {
|
||||
pipe.onAttachedProcessExit();
|
||||
return pipe.toJS(globalThis);
|
||||
} else {
|
||||
subprocess.flags.has_stdin_destructor_called = false;
|
||||
subprocess.weak_file_sink_stdin_ptr = pipe;
|
||||
return pipe.toJSWithDestructor(
|
||||
globalThis,
|
||||
JSC.WebCore.SinkDestructor.Ptr.init(subprocess),
|
||||
);
|
||||
}
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
pub fn finalize(this: *Writable) void {
|
||||
const subprocess: *Subprocess = @fieldParentPtr("stdin", this);
|
||||
if (subprocess.this_jsvalue != .zero) {
|
||||
if (JSC.Codegen.JSSubprocess.stdinGetCached(subprocess.this_jsvalue)) |existing_value| {
|
||||
JSC.WebCore.FileSink.JSSink.setDestroyCallback(existing_value, 0);
|
||||
}
|
||||
}
|
||||
|
||||
return switch (this.*) {
|
||||
.pipe => |pipe| {
|
||||
pipe.deref();
|
||||
|
||||
31
test/js/bun/spawn/spawn-stdin-regression.js
Normal file
31
test/js/bun/spawn/spawn-stdin-regression.js
Normal file
@@ -0,0 +1,31 @@
|
||||
const jsc = require("bun:jsc");
|
||||
|
||||
for (let i = 0; i < 30; i++) {
|
||||
test(`this used to crash :: ${i}`, async () => {
|
||||
const buffer = Buffer.alloc(1024 * 1024, "a");
|
||||
|
||||
async function getStdin() {
|
||||
{
|
||||
let subprocess = Bun.spawn({
|
||||
cmd: [process.argv0, "-e", "Bun.sleep(100)"],
|
||||
stdio: ["pipe", "ignore", "ignore"],
|
||||
});
|
||||
subprocess.unref();
|
||||
subprocess.stdin.write(buffer);
|
||||
process.kill(subprocess.pid, "SIGKILL");
|
||||
await subprocess.stdin.end().catch(() => {});
|
||||
}
|
||||
}
|
||||
|
||||
async function iter() {
|
||||
await getStdin();
|
||||
}
|
||||
|
||||
await Promise.all(Array.from({ length: 200 }, () => iter()));
|
||||
Bun.gc(true);
|
||||
await Bun.sleep(10);
|
||||
const { objectTypeCounts } = jsc.heapStats();
|
||||
console.log("objectTypeCounts:", objectTypeCounts.FileSink, objectTypeCounts.Subprocess);
|
||||
console.log("RSS", (process.memoryUsage.rss() / 1024 / 1024) | 0, "MB");
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user