build tracebacks incrementally while c++ unwinding
Add a tb_next to the BoxedTraceback object, which during normal unwinding is how we add lines to a traceback. For getTraceback() we take advantage fo the fact that each BoxedTraceback can have multiple lines in it, and only create one. Also add BoxedTraceback::Here which is kinda like PyTraceback_Here, except that since we don't have access to the ExcInfo inside it, we have to pass a pointer to the BoxedTraceback*. three wrinkles in traceback generation while unwinding are: 1) if the previous frame was an osr frame (so we should skip the current frame) 2) if the traceback object was passed to raise3, or raise0 was used (treated as a re-raise by cpython) 3) the interpreter map 1 and 2 are fixed by keeping a per-thread interpreter state variable, "unwind_why" ("why" is probably a bad name to use in this context, but cpython's logic uses that word as well), to record if we're in either of those cases. Both cases have the same effect (skip the next traceback line, and reset state to NORMAL.) The interpreter map problem comes about because of the way c++ unwinding works. since ASTInterpreter::execute uses RAII for RegisterHelper, unwinding through the frame causes us to jump to a cleanup block and then resume unwinding (with the IP still in ASTInterpreter::execute). Since the IP is there, we assume the frame is valid and we can look up $rbp in the interpreter map. Given that we just cleaned up the RegisterHelper (and removed the $rbp mapping), we crash. The fix here is to keep the same RegisterHelper in ASTInterpreter::execute, but the ip checked for by the unwinder (and the $rbp in the mapping) correspond to ASTInterpreter::executeInner. Lastly, AST_Interpreter::invoke catches exceptions, so we won't make it to the top-most ASTInterpreter::execute, and so won't add the final line. We make use of BoxedTraceback::Here here as well to add the final line.
Showing
test/tests/incremental_tb.py
0 → 100644
Please register or sign in to comment