This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

Author jbw
Recipients andrei.avk, iritkatriel, jbw, moi90, serhiy.storchaka
Date 2021-10-19.17:02:25
SpamBayes Score -1.0
Marked as misclassified Yes
Message-id <1634662946.0.0.169460932183.issue43656@roundup.psfhosted.org>
In-reply-to
Content
I would like to request that this bug be repopened and fixed.

I've changed (or at least tried to change, I'm not sure if it will let me) the title of the bug to point out that the failure happens in FrameSummary.__init__.  It does not happen in StackSummary.format.

This problem makes the capture_locals=True feature of TracebackException and StackSummary and the "locals" parameter of FrameSummary unreliable.  If any one of the local variables in any frame on the stack is in an inconsistent state such that repr will raise an exception, the processing of the traceback fails.  This kind of inconsistent state is of course likely to happen during debugging, which is precisely when you would want the capture_locals feature to actually work so you can see what is going wrong.

Just one example of an exception traceback being created with an unsafe local variable value in one of the stack frames is in the following line:

  from _pydecimal import Decimal as D; D(None)

The _pydecimal.Decimal.__new__ method raises an exception when it sees a value it doesn't know how to convert to Decimal.  When it does this, the new object it was creating is left in an inconsistent state missing the _sign attribute.  When you try to inspect the resulting exception traceback with traceback.TracebackException(..., capture_locals=True), this raises an exception.

While I was tracking this bug down, I discovered that the traceback.TracebackException.__init__ method has the same problem: it initializes the _str attribute used by the __str__ method quite late and when it raised an exception before this point, the incompletely initialized TracebackException object caused repr to fail.  There's at least one more class in traceback.py that also has this problem, but I don't remember which one it is.

The cascade of exceptions causing exceptions causing exceptions makes the capture_locals feature difficult to use and debug.

Here is a short snippet that reproduces the bug on Python 3.9.7:

import traceback
class TriggerTracebackBug:
    def __init__(self):
        raise RuntimeError("can't build a TriggerTracebackBug object for some reason")
        self._repr = 'if we reached this line, this object would have a repr result'
    def __repr__(self):
        return self._repr
try:
    TriggerTracebackBug()
except Exception as e:
    # this method call fails because there is a stack frame with a local
    # variable (self) such that repr fails on that variable's value:
    traceback.TracebackException.from_exception(e, capture_locals=True)

It's clear that it is too much to expect every class to implement a safe __repr__ method.  So it also seems clear to me that traceback.FrameSummary.__init__ is the place to fix it.

My suggested fix is to replace this line in the latest Lib/traceback.py:

        self.locals = {k: repr(v) for k, v in locals.items()} if locals else None

with something like this code (written in a somewhat awkward way because that helped while I was debugging it):

        if locals:
            d = {}
            self.locals = d
            for k, v in locals.items():
                try:
                    d[k] = repr(v)
                except Exception:
                    d[k] = '''<an exception was raised while trying to format this local variable's value>'''
        else:
            self.locals = None

I've tested this code in an older version of Python and it fixed the problem for me.
History
Date User Action Args
2021-10-19 17:02:26jbwsetrecipients: + jbw, serhiy.storchaka, iritkatriel, moi90, andrei.avk
2021-10-19 17:02:26jbwsetmessageid: <1634662946.0.0.169460932183.issue43656@roundup.psfhosted.org>
2021-10-19 17:02:25jbwlinkissue43656 messages
2021-10-19 17:02:25jbwcreate