Exception.__init__ raises TypeError if overridden and called by subclass
>>> class A(Exception):
... def __init__(self):
... Exception.__init__(self)
...
>>> a = A()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 3, in __init__
TypeError: argument should be a 'Exception' not a 'A'
Why is Exception being enforced here, even if A is a subclass of Exception? That makes it hard to subclass from Exception and override __init__.
Fix crash throwing an incompletely constructed exception
Summary
This fixes my version of the reproducer for #17117, by preventing an incompletely constructed exception from actually being raised.
Testing
I added a test to the testsuite and it passed on the unix standard build.
Trade-offs and Alternatives
In the comments on 17117, there's a link to a different fix in vm.c (to avoid trying to set the traceback info while unwinding) but I think avoiding throwing such an exception in the first place is preferable.
I tried placing the check in mp_obj_is_exception_instance instead, on the theory it might be better (catch more sites where such an object could escape). However, it wasn't a clear size win.
Since the reproducer I found involved throwing an exception from its own constructor, I considered catching exceptions that propagated from a constructor and ensuring super().__init__ was called, similar to the non-error case. However, this would likely have been more code AND it wouldn't fix the case where the exception was thrown and caught within the constructor itself. Plus, we don't have the original reproducer for 17117 and maybe it found another way to do the same thing.