-
Notifications
You must be signed in to change notification settings - Fork 199
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[BUG]: 'wrapper' type casters can crash by raising exceptions through noexcept #497
Comments
Hi @oremanj, I agree that the code here is not as solid as it should be, and that this will require fixes in the future. This will involve adapting the logic to avoid the possibility of an exception being raised in a The reasoning is as follows
Therefore, the casters should return Does that make sense? |
Your reasoning for not wanting to catch exceptions within
This isn't really better though; The basic problem is that there are certain types of failures that can't be noticed until the cast operator executes (because they depend on the exact casted-to type, etc), and the only way it has to signal those failures is raising an exception. So if we want to avoid catching exceptions in casters (or
which can be defined as |
AFAIK the main failure case of The |
Yes, I'll take a shot at implementing this, though likely not for a week or two. Thanks for confirming I wasn't missing something! |
Any news on this? @oremanj ? |
I will hopefully have some time to work on this tomorrow! |
Problem description
nanobind ships with a number of "outer" type casters that are implemented by adding some logic around an "inner" caster, ultimately invoking the inner caster's cast operator in the outer caster's
from_python
method. Examples include the casters forstd::optional<T>
,std::map<K, V>
,nb::typed<T, Ts...>
, etc. Unfortunately,from_python
is noexcept, while cast operators can throw. There are three reasons for a cast operator to throw in nanobind's built-in casters:T&
(whereT
is a bound nanobind type) withNone
char
with a multi-character stringunique_ptr<T>
with aT
that was constructed in PythonThe first of these is generally avoided by passing
cast_flags::disallow_none
when casting a bound type to a non-pointer, but the others can still provoke an exception, which will crash the interpreter when it hits the outer caster'snoexcept
boundary. See the example below.What to do?
disallow_none
into a flag that more generally indicates whether the cast target is a pointer or not; then thechar
caster could also use it to disallow non-single-char strings if the target isn't a pointer.unique_ptr
caster could check for an un-relinquishable object infrom_python
as well as in the cast operator. Unfortunately, it still needs the cast-op check (which can thus cause this issue) to detect cases where one tries to pass the same object for two unique_ptr parameters (or vector elements, etc) in the same function call, because the second conversion won't fail until we've committed to the first one. I can't immediately think of a way to robustify this, but it might be possible.Reproducible example code
The text was updated successfully, but these errors were encountered: