From 4abb9e38b211439b1a21b46d065cea889ae11748 Mon Sep 17 00:00:00 2001 From: robobun Date: Thu, 16 Jul 2026 20:29:03 +0000 Subject: [PATCH] Pass the error instance to the stack string callback ErrorInstance::finalizeUnconditionally computes and caches the stack string through VM::onComputeErrorInfo, which does not receive the ErrorInstance, so the embedder cannot include the error's name and message in the cached string. A later .stack access serves that cached string and the "Name: message" head line is lost. Add an optional VM::onComputeErrorInfoWithInstance callback that also receives the instance and is preferred over onComputeErrorInfo when set. The existing callback keeps its signature and behavior, so current embedders are unaffected until they opt in. Needed for oven-sh/bun#34398. --- Source/JavaScriptCore/runtime/ErrorInstance.cpp | 11 ++++++++++- Source/JavaScriptCore/runtime/VM.h | 6 ++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/Source/JavaScriptCore/runtime/ErrorInstance.cpp b/Source/JavaScriptCore/runtime/ErrorInstance.cpp index 8cb916db573db..60d388797d614 100644 --- a/Source/JavaScriptCore/runtime/ErrorInstance.cpp +++ b/Source/JavaScriptCore/runtime/ErrorInstance.cpp @@ -372,9 +372,18 @@ void ErrorInstance::computeErrorInfo(VM& vm, bool allocationAllowed) UNUSED_PARAM(allocationAllowed); if (m_stackTrace && !m_stackTrace->isEmpty()) { + auto& fnWithInstance = vm.onComputeErrorInfoWithInstance(); auto& fn = vm.onComputeErrorInfo(); WTF::String stackString; - if (fn) { + if (fnWithInstance) { + // Preferred over onComputeErrorInfo: passing the instance lets the + // callback include the error's name and message in the stack string + // even when this runs from the GC finalizer (finalizeUnconditionally). + if (m_stackPropertyAlreadyMaterialized) + stackString = emptyString(); + else + stackString = fnWithInstance(vm, *m_stackTrace.get(), m_lineColumn.line, m_lineColumn.column, m_sourceURL, this, this->bunErrorData()); + } else if (fn) { if (m_stackPropertyAlreadyMaterialized) stackString = emptyString(); else diff --git a/Source/JavaScriptCore/runtime/VM.h b/Source/JavaScriptCore/runtime/VM.h index 6df90ecf4b5b8..b0c8fac58bfbc 100644 --- a/Source/JavaScriptCore/runtime/VM.h +++ b/Source/JavaScriptCore/runtime/VM.h @@ -170,6 +170,7 @@ constexpr bool validateDFGDoesGC = ENABLE_DFG_DOES_GC_VALIDATION; #if USE(BUN_JSC_ADDITIONS) using StackTraceAppenderFunction = WTF::Function& stackTrace, size_t maxToAppend)>; using ErrorInfoFunction = WTF::Function& stackTrace, unsigned& line, unsigned& column, String& sourceURL, void* bunErrorData)>; +using ErrorInfoWithInstanceFunction = WTF::Function& stackTrace, unsigned& line, unsigned& column, String& sourceURL, JSC::JSObject* errorInstance, void* bunErrorData)>; using ErrorInfoFunctionJSValue = WTF::Function& stackTrace, unsigned& line, unsigned& column, String& sourceURL, JSC::JSObject*, void* bunErrorData)>; #endif @@ -1062,6 +1063,9 @@ class VM : public ThreadSafeRefCountedWithSuppressingSaferCPPChecking { const ErrorInfoFunction& onComputeErrorInfo() const { return m_onComputeErrorInfo; } ErrorInfoFunction& onComputeErrorInfo() { return m_onComputeErrorInfo; } + const ErrorInfoWithInstanceFunction& onComputeErrorInfoWithInstance() const { return m_onComputeErrorInfoWithInstance; } + ErrorInfoWithInstanceFunction& onComputeErrorInfoWithInstance() { return m_onComputeErrorInfoWithInstance; } + const ErrorInfoFunctionJSValue& onComputeErrorInfoJSValue() const { return m_onComputeErrorInfoJSValue; } ErrorInfoFunctionJSValue& onComputeErrorInfoJSValue() { return m_onComputeErrorInfoJSValue; } @@ -1070,6 +1074,7 @@ class VM : public ThreadSafeRefCountedWithSuppressingSaferCPPChecking { void setOnAppendStackTrace(StackTraceAppenderFunction&& function) { m_onAppendStackTrace = WTF::move(function); } void setOnComputeErrorInfo(ErrorInfoFunction&& function) { m_onComputeErrorInfo = WTF::move(function); } + void setOnComputeErrorInfoWithInstance(ErrorInfoWithInstanceFunction&& function) { m_onComputeErrorInfoWithInstance = WTF::move(function); } void setOnComputeErrorInfoJSValue(ErrorInfoFunctionJSValue&& function) { m_onComputeErrorInfoJSValue = WTF::move(function); } void setComputeLineColumnWithSourcemap(WTF::Function&& function) { m_computeLineColumnWithSourcemap = WTF::move(function); } #endif @@ -1287,6 +1292,7 @@ class VM : public ThreadSafeRefCountedWithSuppressingSaferCPPChecking { WTF::Function m_onEachMicrotaskTick; #if USE(BUN_JSC_ADDITIONS) ErrorInfoFunction m_onComputeErrorInfo; + ErrorInfoWithInstanceFunction m_onComputeErrorInfoWithInstance; ErrorInfoFunctionJSValue m_onComputeErrorInfoJSValue; StackTraceAppenderFunction m_onAppendStackTrace; WTF::Function m_computeLineColumnWithSourcemap;