Exceptions sometimes lead to "terminate called"
When running the following code snippet, a C++ exception is correctly reported in an interactive Python session:
>>> from pyintervalxt import IntervalExchangeTransformation
>>> iet = IntervalExchangeTransformation((18, 3), (1, 0))
>>> iet
[a: 18] [b: 3] / [b] [a]
>>> from pyeantic import eantic
>>> L = eantic.renf("a^3 - a^2 - a - 1", "a", "[1.84 +/- 0.01]")
>>> lengths = [L.gen(), eantic.renf_elem(L, "-3*a^2 + 2*a - 1")]
>>> IntervalExchangeTransformation(lengths, [1, 0])
---------------------------------------------------------------------------
TypeError: none of the 4 overloaded methods succeeded. Full details:
Lengths<std::vector<eantic::renf_elem_class> >::Lengths<std::vector<eantic::renf_elem_class> >(intervalxt::cppyy::Lengths<std::vector<eantic::renf_elem_class> >&&) =>
ValueError: could not convert argument 1 (object is not an rvalue)
Lengths<std::vector<eantic::renf_elem_class> >::Lengths<std::vector<eantic::renf_elem_class> >(const intervalxt::cppyy::Lengths<std::vector<eantic::renf_elem_class> >&) =>
TypeError: could not convert argument 1
Lengths<std::vector<eantic::renf_elem_class> >::Lengths<std::vector<eantic::renf_elem_class> >(const std::vector<eantic::renf_elem_class>&) =>
invalid_argument: all lengths must be non-negative
Lengths<std::vector<eantic::renf_elem_class> >::Lengths<std::vector<eantic::renf_elem_class> >() =>
TypeError: takes at most 0 arguments (1 given)
However, later in the same session, the same invocation causes a crash:
>>> iet = IntervalExchangeTransformation((18, 3), (1, 0))
>>> from pickle import loads, dumps
>>> loads(dumps(iet))
[a: 18] [b: 3] / [b] [a]
>>> lengths = [L.gen(), eantic.renf_elem(L, "-3*a^2 + 2*a - 1")]
>>> IntervalExchangeTransformation(lengths, [1, 0])
terminate called after throwing an instance of 'std::invalid_argument'
what(): all lengths must be non-negative
Since the same exception was apparently thrown, I don't understand why the loads and dumps on an unrelated object, made it so that this time the exception could not be caught and handed over to Python.
Unfortunately, I could not find a short reproducer for this yet. I can reproduce the above on Linux in the following conda environment:
conda create -n terminate -c flatsurf pyintervalxt pyeantic
conda activate terminate
python
I'll have a look, but all method calls into C++ have a catch (...), so the only reason I can think of, is that the C++ exception has two type_info's. Nominally, the easiest way to "achieve" that is to have one JIT-ed and one linked, but a) I haven't seen that to be a problem on Linux; b) a standard exception is a weird one for this to happen to; and c) I don't see where this JIT-ing would occur. So, I'm a bit at a loss as to how this can occur ...