Skip to content

Commit

Permalink
Fixes #14716 (#14834)
Browse files Browse the repository at this point in the history
  • Loading branch information
Jarred-Sumner authored Oct 26, 2024
1 parent 50d80a8 commit 2456d70
Show file tree
Hide file tree
Showing 2 changed files with 55 additions and 11 deletions.
32 changes: 21 additions & 11 deletions src/bun.js/bindings/ZigGlobalObject.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -285,30 +285,40 @@ static JSValue formatStackTraceToJSValue(JSC::VM& vm, Zig::GlobalObject* globalO
size_t framesCount = callSites->length();

WTF::StringBuilder sb;

if (JSC::JSValue errorMessage = errorObject->getIfPropertyExists(lexicalGlobalObject, vm.propertyNames->message)) {
RETURN_IF_EXCEPTION(scope, {});
auto* str = errorMessage.toString(lexicalGlobalObject);
RETURN_IF_EXCEPTION(scope, {});
if (str->length() > 0) {
auto value = str->value(lexicalGlobalObject);
RETURN_IF_EXCEPTION(scope, {});
sb.append("Error: "_s);
sb.append(str->value(lexicalGlobalObject).data);
sb.append(value.data);
} else {
sb.append("Error"_s);
}
} else {
sb.append("Error"_s);
}

if (framesCount > 0) {
sb.append("\n"_s);
}

for (size_t i = 0; i < framesCount; i++) {
sb.append("\n at "_s);

JSC::JSValue callSiteValue = callSites->getIndex(lexicalGlobalObject, i);
CallSite* callSite = JSC::jsDynamicCast<CallSite*>(callSiteValue);
sb.append(" at "_s);
callSite->formatAsString(vm, lexicalGlobalObject, sb);
RETURN_IF_EXCEPTION(scope, {});
if (i != framesCount - 1) {
sb.append("\n"_s);

if (CallSite* callSite = JSC::jsDynamicCast<CallSite*>(callSiteValue)) {
callSite->formatAsString(vm, lexicalGlobalObject, sb);
RETURN_IF_EXCEPTION(scope, {});
} else {
// This matches Node.js / V8's behavior
// It can become "at [object Object]" if the object is not a CallSite
auto* str = callSiteValue.toString(lexicalGlobalObject);
RETURN_IF_EXCEPTION(scope, {});
auto value = str->value(lexicalGlobalObject);
RETURN_IF_EXCEPTION(scope, {});
sb.append(value.data);
}
}

Expand Down Expand Up @@ -684,8 +694,8 @@ static JSValue computeErrorInfoWithPrepareStackTrace(JSC::VM& vm, Zig::GlobalObj

for (size_t i = 0; i < framesCount; i++) {
JSC::JSValue callSiteValue = callSites.at(i);
CallSite* callSite = JSC::jsDynamicCast<CallSite*>(callSiteValue);
if (remappedFrames[i].remapped) {
CallSite* callSite = JSC::jsCast<CallSite*>(callSiteValue);
callSite->setColumnNumber(remappedFrames[i].position.column());
callSite->setLineNumber(remappedFrames[i].position.line());
}
Expand Down
34 changes: 34 additions & 0 deletions test/js/node/v8/capture-stack-trace.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -663,3 +663,37 @@ test("calling .stack on a non-materialized Error updates the stack properly", fu
expect(stack).toContain("hey");
expect(stack).toContain("wrapped");
});

test("Error.prepareStackTrace on an array with non-CallSite objects doesn't crash", () => {
const result = Error.prepareStackTrace(new Error("ok"), [{ a: 1 }, { b: 2 }, { c: 3 }]);
expect(result).toBe("Error: ok\n at [object Object]\n at [object Object]\n at [object Object]");
});

test("Error.prepareStackTrace calls toString()", () => {
const result = Error.prepareStackTrace(new Error("ok"), [
{ a: 1 },
{ b: 2 },
{
c: 3,
toString() {
return "potato";
},
},
]);
expect(result).toBe("Error: ok\n at [object Object]\n at [object Object]\n at potato");
});

test("Error.prepareStackTrace propagates exceptions", () => {
expect(() =>
Error.prepareStackTrace(new Error("ok"), [
{ a: 1 },
{ b: 2 },
{
c: 3,
toString() {
throw new Error("hi");
},
},
]),
).toThrow("hi");
});

0 comments on commit 2456d70

Please sign in to comment.