Skip to content

Commit e5a82e6

Browse files
remove duplicate JS stack trace
1 parent 6d447c6 commit e5a82e6

File tree

4 files changed

+37
-11
lines changed

4 files changed

+37
-11
lines changed

include/setSpiderMonkeyException.hh

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,9 @@
1818
*
1919
* @param cx - pointer to the JS context
2020
* @param exceptionStack - reference to the SpiderMonkey exception stack
21+
* @param printStack - whether or not to print the JS stack
2122
*/
22-
PyObject *getExceptionString(JSContext *cx, const JS::ExceptionStack &exceptionStack);
23+
PyObject *getExceptionString(JSContext *cx, const JS::ExceptionStack &exceptionStack, bool printStack);
2324

2425
/**
2526
* @brief This function sets a python error under the assumption that a JS_* function call has failed. Do not call this function if that is not the case.

src/ExceptionType.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ ExceptionType::ExceptionType(JSContext *cx, JS::HandleObject error) {
2727
// Convert the JS Error object to a Python string
2828
JS::RootedValue errValue(cx, JS::ObjectValue(*error)); // err
2929
JS::RootedObject errStack(cx, JS::ExceptionStackOrNull(error)); // err.stack
30-
PyObject *errStr = getExceptionString(cx, JS::ExceptionStack(cx, errValue, errStack));
30+
PyObject *errStr = getExceptionString(cx, JS::ExceptionStack(cx, errValue, errStack), true);
3131

3232
// Construct a new SpiderMonkeyError python object
3333
// pyObject = SpiderMonkeyError(errStr)

src/jsTypeFactory.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -288,7 +288,7 @@ void setPyException(JSContext *cx) {
288288
}
289289

290290
PyObject *type, *value, *traceback;
291-
PyErr_Fetch(&type, &value, &traceback); // also clears the error indicator
291+
PyErr_Fetch(&type, &value, &traceback);
292292

293293
JSObject *jsException = ExceptionType::toJsError(cx, value, traceback);
294294

src/setSpiderMonkeyException.cc

Lines changed: 33 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
#include <codecvt>
1919
#include <locale>
2020

21-
PyObject *getExceptionString(JSContext *cx, const JS::ExceptionStack &exceptionStack) {
21+
PyObject *getExceptionString(JSContext *cx, const JS::ExceptionStack &exceptionStack, bool printStack) {
2222
JS::ErrorReportBuilder reportBuilder(cx);
2323
if (!reportBuilder.init(cx, exceptionStack, JS::ErrorReportBuilder::WithSideEffects /* may call the `toString` method if an object is thrown */)) {
2424
return PyUnicode_FromString("Spidermonkey set an exception, but could not initialize the error report.");
@@ -56,12 +56,13 @@ PyObject *getExceptionString(JSContext *cx, const JS::ExceptionStack &exceptionS
5656
// print out the SpiderMonkey error message
5757
outStrStream << reportBuilder.toStringResult().c_str() << "\n";
5858

59-
60-
JS::RootedObject stackObj(cx, exceptionStack.stack());
61-
if (stackObj.get()) {
62-
JS::RootedString stackStr(cx);
63-
BuildStackString(cx, nullptr, stackObj, &stackStr, /* indent */ 2, js::StackFormat::SpiderMonkey);
64-
outStrStream << "Stack Trace: \n" << StrType(cx, stackStr).getValue();
59+
if (printStack) {
60+
JS::RootedObject stackObj(cx, exceptionStack.stack());
61+
if (stackObj.get()) {
62+
JS::RootedString stackStr(cx);
63+
BuildStackString(cx, nullptr, stackObj, &stackStr, /* indent */ 2, js::StackFormat::SpiderMonkey);
64+
outStrStream << "Stack Trace: \n" << StrType(cx, stackStr).getValue();
65+
}
6566
}
6667

6768
return PyUnicode_FromString(outStrStream.str().c_str());
@@ -80,11 +81,35 @@ void setSpiderMonkeyException(JSContext *cx) {
8081
PyErr_SetString(SpiderMonkeyError, "Spidermonkey set an exception, but was unable to retrieve it.");
8182
return;
8283
}
84+
85+
// check if it is a Python Exception and already has a stack trace
86+
bool printStack;
87+
88+
JS::Rooted<JS::Value> exn(cx);
89+
JS_GetPendingException(cx, &exn);
90+
if (exn.isObject()) {
91+
JS::RootedObject exnObj(cx, &exn.toObject());
92+
JS::RootedValue tmp(cx);
93+
if (!JS_GetProperty(cx, exnObj, "message", &tmp)) {
94+
printStack = true;
95+
}
96+
else if (tmp.isString()) {
97+
JS::RootedString rootedStr(cx, tmp.toString());
98+
printStack = strstr(JS_EncodeStringToUTF8(cx, rootedStr).get(), "JS Stack Trace") == NULL;
99+
}
100+
else {
101+
printStack = true;
102+
}
103+
}
104+
else {
105+
printStack = true;
106+
}
107+
83108
JS_ClearPendingException(cx);
84109

85110
// `PyErr_SetString` uses `PyErr_SetObject` with `PyUnicode_FromString` under the hood
86111
// see https://github.com/python/cpython/blob/3.9/Python/errors.c#L234-L236
87-
PyObject *errStr = getExceptionString(cx, exceptionStack);
112+
PyObject *errStr = getExceptionString(cx, exceptionStack, printStack);
88113
PyErr_SetObject(SpiderMonkeyError, errStr);
89114
Py_XDECREF(errStr);
90115
}

0 commit comments

Comments
 (0)