This commit is contained in:
Jarred Sumner
2025-06-27 22:05:20 -07:00
committed by GitHub
parent a067619f13
commit dd67cda545
8 changed files with 33 additions and 36 deletions

View File

@@ -380,7 +380,7 @@ pub const UDPSocket = struct {
const globalThis = this.globalThis;
const vm = globalThis.bunVM();
if (err.isTerminationException(vm.jsc)) {
if (err.isTerminationException()) {
return;
}
if (callback == .zero) {

View File

@@ -22,9 +22,8 @@ const size = 56;
const alignment = 8;
bytes: [size]u8 align(alignment),
global: *jsc.JSGlobalObject,
/// Pointer to `bytes`, set by `init()`, used to assert that the location did not change
location: if (Environment.allow_assert) *u8 else void,
location: if (Environment.ci_assert) *u8 else void,
enabled: bool,
pub const Enable = enum {
@@ -46,13 +45,13 @@ pub fn init(
/// If you need to do something different when there is an exception, leave enabled.
/// If you are only using the scope to prove you handle exceptions correctly, you can pass
/// `Environment.allow_assert` as `enabled`.
enable_condition: Enable,
comptime enable_condition: Enable,
) void {
const enabled = switch (enable_condition) {
const enabled = comptime switch (enable_condition) {
.enabled => true,
.assertions_only => Environment.allow_assert,
.assertions_only => Environment.ci_assert,
};
if (enabled) {
if (comptime enabled) {
CatchScope__construct(
&self.bytes,
global,
@@ -65,8 +64,7 @@ pub fn init(
}
self.* = .{
.bytes = self.bytes,
.global = global,
.location = if (Environment.allow_assert) &self.bytes[0],
.location = if (Environment.ci_assert) &self.bytes[0],
.enabled = enabled,
};
}
@@ -86,14 +84,14 @@ pub fn hasException(self: *CatchScope) bool {
/// Get the thrown exception if it exists (like scope.exception() in C++)
pub fn exception(self: *CatchScope) ?*jsc.Exception {
if (Environment.allow_assert) bun.assert(self.location == &self.bytes[0]);
if (comptime Environment.ci_assert) bun.assert(self.location == &self.bytes[0]);
if (!self.enabled) return null;
return CatchScope__pureException(&self.bytes);
}
/// Get the thrown exception if it exists, or if an unhandled trap causes an exception to be thrown
pub fn exceptionIncludingTraps(self: *CatchScope) ?*jsc.Exception {
if (Environment.allow_assert) bun.assert(self.location == &self.bytes[0]);
if (comptime Environment.ci_assert) bun.assert(self.location == &self.bytes[0]);
if (!self.enabled) return null;
return CatchScope__exceptionIncludingTraps(&self.bytes);
}
@@ -106,7 +104,7 @@ pub fn returnIfException(self: *CatchScope) bun.JSError!void {
/// Asserts there has not been any exception thrown.
pub fn assertNoException(self: *CatchScope) void {
if (Environment.allow_assert) {
if (comptime Environment.ci_assert) {
if (self.exception()) |e| self.assertionFailure(e);
}
}
@@ -115,7 +113,7 @@ pub fn assertNoException(self: *CatchScope) void {
/// Prefer over `assert(scope.hasException() == ...)` because if there is an unexpected exception,
/// this function prints a trace of where it was thrown.
pub fn assertExceptionPresenceMatches(self: *CatchScope, should_have_exception: bool) void {
if (Environment.allow_assert) {
if (comptime Environment.ci_assert) {
// paranoid; will only fail if you manually changed enabled to false
bun.assert(self.enabled);
if (should_have_exception) {
@@ -131,20 +129,17 @@ pub fn assertExceptionPresenceMatches(self: *CatchScope, should_have_exception:
/// If non-termination exception, assertion failure.
pub fn assertNoExceptionExceptTermination(self: *CatchScope) bun.JSExecutionTerminated!void {
bun.assert(self.enabled);
return if (self.exception()) |e|
if (jsc.JSValue.fromCell(e).isTerminationException(self.global.vm()))
error.JSExecutionTerminated
else if (Environment.allow_assert)
self.assertionFailure(e)
else
// we got an exception other than the termination one, but we can't assert.
// treat this like the termination exception so we still bail out
error.JSExecutionTerminated
else {};
if (self.exception()) |e| {
if (jsc.JSValue.fromCell(e).isTerminationException())
return error.JSExecutionTerminated
else if (comptime Environment.ci_assert)
self.assertionFailure(e);
// Unconditionally panicing here is worse for our users.
}
}
pub fn deinit(self: *CatchScope) void {
if (Environment.allow_assert) bun.assert(self.location == &self.bytes[0]);
if (comptime Environment.ci_assert) bun.assert(self.location == &self.bytes[0]);
if (!self.enabled) return;
CatchScope__destruct(&self.bytes);
self.bytes = undefined;

View File

@@ -553,7 +553,7 @@ pub const JSGlobalObject = opaque {
///
pub fn reportActiveExceptionAsUnhandled(this: *JSGlobalObject, err: bun.JSError) void {
const exception = this.takeException(err);
if (!exception.isTerminationException(this.vm())) {
if (!exception.isTerminationException()) {
_ = this.bunVM().uncaughtException(this, exception, false);
}
}

View File

@@ -1138,9 +1138,9 @@ pub const JSValue = enum(i64) {
null;
}
extern fn JSC__JSValue__isTerminationException(this: JSValue, vm: *VM) bool;
pub fn isTerminationException(this: JSValue, vm: *VM) bool {
return JSC__JSValue__isTerminationException(this, vm);
extern fn JSC__JSValue__isTerminationException(this: JSValue) bool;
pub fn isTerminationException(this: JSValue) bool {
return JSC__JSValue__isTerminationException(this);
}
extern fn JSC__JSValue__toZigException(this: JSValue, global: *JSGlobalObject, exception: *ZigException) void;

View File

@@ -5287,10 +5287,13 @@ void JSC__VM__setExecutionTimeLimit(JSC::VM* vm, double limit)
watchdog.setTimeLimit(WTF::Seconds { limit });
}
bool JSC__JSValue__isTerminationException(JSC::EncodedJSValue JSValue0, JSC::VM* arg1)
bool JSC__JSValue__isTerminationException(JSC::EncodedJSValue JSValue0)
{
JSC::Exception* exception = JSC::jsDynamicCast<JSC::Exception*>(JSC::JSValue::decode(JSValue0));
return exception != NULL && arg1->isTerminationException(exception);
if (exception == nullptr)
return false;
return exception->vm().isTerminationException(exception);
}
extern "C" void JSC__Exception__getStackTrace(JSC::Exception* arg0, JSC::JSGlobalObject* global, ZigStackTrace* trace)

View File

@@ -256,7 +256,7 @@ CPP_DECL bool JSC__JSValue__isObject(JSC::EncodedJSValue JSValue0);
CPP_DECL bool JSC__JSValue__isPrimitive(JSC::EncodedJSValue JSValue0);
CPP_DECL bool JSC__JSValue__isSameValue(JSC::EncodedJSValue JSValue0, JSC::EncodedJSValue JSValue1, JSC::JSGlobalObject* arg2);
CPP_DECL bool JSC__JSValue__isSymbol(JSC::EncodedJSValue JSValue0);
CPP_DECL bool JSC__JSValue__isTerminationException(JSC::EncodedJSValue JSValue0, JSC::VM* arg1);
CPP_DECL bool JSC__JSValue__isTerminationException(JSC::EncodedJSValue JSValue0);
CPP_DECL bool JSC__JSValue__isUInt32AsAnyInt(JSC::EncodedJSValue JSValue0);
CPP_DECL bool JSC__JSValue__jestDeepEquals(JSC::EncodedJSValue JSValue0, JSC::EncodedJSValue JSValue1, JSC::JSGlobalObject* arg2);
CPP_DECL bool JSC__JSValue__jestDeepMatch(JSC::EncodedJSValue JSValue0, JSC::EncodedJSValue JSValue1, JSC::JSGlobalObject* arg2, bool arg3);

View File

@@ -86,11 +86,9 @@ pub export fn Bun__queueTaskWithTimeout(global: *JSGlobalObject, task: *JSC.CppT
pub export fn Bun__reportUnhandledError(globalObject: *JSGlobalObject, value: JSValue) callconv(.C) JSValue {
JSC.markBinding(@src());
// This JSGlobalObject might not be the main script execution context
// See the crash in https://github.com/oven-sh/bun/issues/9778
const vm = JSC.VirtualMachine.get();
if (!value.isTerminationException(vm.jsc)) {
_ = vm.uncaughtException(globalObject, value, false);
if (!value.isTerminationException()) {
_ = globalObject.bunVM().uncaughtException(globalObject, value, false);
}
return .js_undefined;
}

View File

@@ -26,6 +26,7 @@ pub const isX86 = @import("builtin").target.cpu.arch.isX86();
pub const isX64 = @import("builtin").target.cpu.arch == .x86_64;
pub const isMusl = builtin.target.abi.isMusl();
pub const allow_assert = isDebug or isTest or std.builtin.Mode.ReleaseSafe == @import("builtin").mode;
pub const ci_assert = isDebug or isTest or enable_asan or (std.builtin.Mode.ReleaseSafe == @import("builtin").mode and is_canary);
pub const show_crash_trace = isDebug or isTest or enable_asan;
/// All calls to `@export` should be gated behind this check, so that code
/// generators that compile Zig code know not to reference and compile a ton of