Skip to content

Commit e72d958

Browse files
committed
detail::error_string: handle call stacks that switch between C++ and Python multiple times
1 parent fbec17c commit e72d958

File tree

1 file changed

+21
-11
lines changed

1 file changed

+21
-11
lines changed

include/pybind11/cast.h

Lines changed: 21 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -136,19 +136,29 @@ PYBIND11_NOINLINE inline std::string error_string() {
136136

137137
PyErr_NormalizeException(&scope.type, &scope.value, &scope.trace);
138138

139+
#if PY_MAJOR_VERSION >= 3
140+
if (scope.trace != nullptr)
141+
PyException_SetTraceback(scope.value, scope.trace);
142+
#endif
143+
139144
if (scope.trace) {
140-
PyFrameObject *frame = ((PyTracebackObject *) scope.trace)->tb_frame;
141-
if (frame) {
142-
errorString += "\n\nAt:\n";
143-
while (frame) {
144-
int lineno = PyFrame_GetLineNumber(frame);
145-
errorString +=
146-
" " + handle(frame->f_code->co_filename).cast<std::string>() +
147-
"(" + std::to_string(lineno) + "): " +
148-
handle(frame->f_code->co_name).cast<std::string>() + "\n";
149-
frame = frame->f_back;
150-
}
145+
PyTracebackObject *trace = (PyTracebackObject *) scope.trace;
146+
147+
/* Get the deepest trace possible */
148+
while (trace->tb_next)
149+
trace = trace->tb_next;
150+
151+
PyFrameObject *frame = trace->tb_frame;
152+
errorString += "\n\nAt:\n";
153+
while (frame) {
154+
int lineno = PyFrame_GetLineNumber(frame);
155+
errorString +=
156+
" " + handle(frame->f_code->co_filename).cast<std::string>() +
157+
"(" + std::to_string(lineno) + "): " +
158+
handle(frame->f_code->co_name).cast<std::string>() + "\n";
159+
frame = frame->f_back;
151160
}
161+
trace = trace->tb_next;
152162
}
153163

154164
return errorString;

0 commit comments

Comments
 (0)