mirror of
https://github.com/oven-sh/bun
synced 2026-02-09 10:28:47 +00:00
Fix crash initializing process stdio streams while process is overridden (#19978)
This commit is contained in:
@@ -2030,13 +2030,14 @@ enum class BunProcessStdinFdType : int32_t {
|
||||
extern "C" BunProcessStdinFdType Bun__Process__getStdinFdType(void*, int fd);
|
||||
|
||||
extern "C" void Bun__ForceFileSinkToBeSynchronousForProcessObjectStdio(JSC::JSGlobalObject*, JSC::EncodedJSValue);
|
||||
static JSValue constructStdioWriteStream(JSC::JSGlobalObject* globalObject, int fd)
|
||||
static JSValue constructStdioWriteStream(JSC::JSGlobalObject* globalObject, JSC::JSObject* processObject, int fd)
|
||||
{
|
||||
auto& vm = JSC::getVM(globalObject);
|
||||
auto scope = DECLARE_CATCH_SCOPE(vm);
|
||||
|
||||
JSC::JSFunction* getStdioWriteStream = JSC::JSFunction::create(vm, globalObject, processObjectInternalsGetStdioWriteStreamCodeGenerator(vm), globalObject);
|
||||
JSC::MarkedArgumentBuffer args;
|
||||
args.append(processObject);
|
||||
args.append(JSC::jsNumber(fd));
|
||||
args.append(jsBoolean(bun_stdio_tty[fd]));
|
||||
BunProcessStdinFdType fdType = Bun__Process__getStdinFdType(Bun::vm(vm), fd);
|
||||
@@ -2045,8 +2046,11 @@ static JSValue constructStdioWriteStream(JSC::JSGlobalObject* globalObject, int
|
||||
JSC::CallData callData = JSC::getCallData(getStdioWriteStream);
|
||||
|
||||
auto result = JSC::profiledCall(globalObject, ProfilingReason::API, getStdioWriteStream, callData, globalObject->globalThis(), args);
|
||||
scope.assertNoExceptionExceptTermination();
|
||||
CLEAR_AND_RETURN_IF_EXCEPTION(scope, jsUndefined());
|
||||
if (auto* exception = scope.exception()) {
|
||||
Zig::GlobalObject::reportUncaughtExceptionAtEventLoop(globalObject, exception);
|
||||
scope.clearException();
|
||||
return jsUndefined();
|
||||
}
|
||||
|
||||
ASSERT_WITH_MESSAGE(JSC::isJSArray(result), "Expected an array from getStdioWriteStream");
|
||||
JSC::JSArray* resultObject = JSC::jsCast<JSC::JSArray*>(result);
|
||||
@@ -2077,12 +2081,12 @@ static JSValue constructStdioWriteStream(JSC::JSGlobalObject* globalObject, int
|
||||
|
||||
static JSValue constructStdout(VM& vm, JSObject* processObject)
|
||||
{
|
||||
return constructStdioWriteStream(processObject->globalObject(), 1);
|
||||
return constructStdioWriteStream(processObject->globalObject(), processObject, 1);
|
||||
}
|
||||
|
||||
static JSValue constructStderr(VM& vm, JSObject* processObject)
|
||||
{
|
||||
return constructStdioWriteStream(processObject->globalObject(), 2);
|
||||
return constructStdioWriteStream(processObject->globalObject(), processObject, 2);
|
||||
}
|
||||
|
||||
#if OS(WINDOWS)
|
||||
@@ -2092,17 +2096,22 @@ static JSValue constructStderr(VM& vm, JSObject* processObject)
|
||||
static JSValue constructStdin(VM& vm, JSObject* processObject)
|
||||
{
|
||||
auto* globalObject = processObject->globalObject();
|
||||
auto scope = DECLARE_THROW_SCOPE(vm);
|
||||
JSC::JSFunction* getStdioWriteStream = JSC::JSFunction::create(vm, globalObject, processObjectInternalsGetStdinStreamCodeGenerator(vm), globalObject);
|
||||
auto scope = DECLARE_CATCH_SCOPE(vm);
|
||||
JSC::JSFunction* getStdinStream = JSC::JSFunction::create(vm, globalObject, processObjectInternalsGetStdinStreamCodeGenerator(vm), globalObject);
|
||||
JSC::MarkedArgumentBuffer args;
|
||||
args.append(processObject);
|
||||
args.append(JSC::jsNumber(STDIN_FILENO));
|
||||
args.append(jsBoolean(bun_stdio_tty[STDIN_FILENO]));
|
||||
BunProcessStdinFdType fdType = Bun__Process__getStdinFdType(Bun::vm(vm), STDIN_FILENO);
|
||||
args.append(jsNumber(static_cast<int32_t>(fdType)));
|
||||
JSC::CallData callData = JSC::getCallData(getStdioWriteStream);
|
||||
JSC::CallData callData = JSC::getCallData(getStdinStream);
|
||||
|
||||
auto result = JSC::profiledCall(globalObject, ProfilingReason::API, getStdioWriteStream, callData, globalObject, args);
|
||||
RETURN_IF_EXCEPTION(scope, {});
|
||||
auto result = JSC::profiledCall(globalObject, ProfilingReason::API, getStdinStream, callData, globalObject, args);
|
||||
if (auto* exception = scope.exception()) {
|
||||
Zig::GlobalObject::reportUncaughtExceptionAtEventLoop(globalObject, exception);
|
||||
scope.clearException();
|
||||
return jsUndefined();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@@ -30,8 +30,13 @@ const enum BunProcessStdinFdType {
|
||||
socket = 2,
|
||||
}
|
||||
|
||||
export function getStdioWriteStream(fd, isTTY: boolean, _fdType: BunProcessStdinFdType) {
|
||||
$assert(typeof fd === "number", `Expected fd to be a number, got ${typeof fd}`);
|
||||
export function getStdioWriteStream(
|
||||
process: typeof globalThis.process,
|
||||
fd: number,
|
||||
isTTY: boolean,
|
||||
_fdType: BunProcessStdinFdType,
|
||||
) {
|
||||
$assert(fd === 1 || fd === 2, `Expected fd to be 1 or 2, got ${fd}`);
|
||||
|
||||
let stream;
|
||||
if (isTTY) {
|
||||
@@ -74,9 +79,14 @@ export function getStdioWriteStream(fd, isTTY: boolean, _fdType: BunProcessStdin
|
||||
return [stream, underlyingSink];
|
||||
}
|
||||
|
||||
export function getStdinStream(fd, isTTY: boolean, fdType: BunProcessStdinFdType) {
|
||||
export function getStdinStream(
|
||||
process: typeof globalThis.process,
|
||||
fd: number,
|
||||
isTTY: boolean,
|
||||
fdType: BunProcessStdinFdType,
|
||||
) {
|
||||
$assert(fd === 0);
|
||||
const native = Bun.stdin.stream();
|
||||
// @ts-expect-error
|
||||
const source = native.$bunNativePtr;
|
||||
|
||||
var reader: ReadableStreamDefaultReader<Uint8Array> | undefined;
|
||||
@@ -246,7 +256,12 @@ export function getStdinStream(fd, isTTY: boolean, fdType: BunProcessStdinFdType
|
||||
|
||||
return stream;
|
||||
}
|
||||
export function initializeNextTickQueue(process, nextTickQueue, drainMicrotasksFn, reportUncaughtExceptionFn) {
|
||||
export function initializeNextTickQueue(
|
||||
process: typeof globalThis.process,
|
||||
nextTickQueue,
|
||||
drainMicrotasksFn,
|
||||
reportUncaughtExceptionFn,
|
||||
) {
|
||||
var queue;
|
||||
var process;
|
||||
var nextTickQueue = nextTickQueue;
|
||||
|
||||
@@ -1114,3 +1114,20 @@ it("should handle user assigned `default` properties", async () => {
|
||||
|
||||
await promise;
|
||||
});
|
||||
|
||||
it.each(["stdin", "stdout", "stderr"])("%s stream accessor should handle exceptions without crashing", stream => {
|
||||
expect([
|
||||
/* js */ `
|
||||
const old = process;
|
||||
process = null;
|
||||
try {
|
||||
old.${stream};
|
||||
} catch {}
|
||||
if (typeof old.${stream} !== "undefined") {
|
||||
console.log("wrong");
|
||||
}
|
||||
`,
|
||||
"",
|
||||
1,
|
||||
]).toRunInlineFixture();
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user