Skip to content
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

fix: throwing repr caused a segfault #2389

Merged
merged 2 commits into from
Aug 18, 2020
Merged

Conversation

henryiii
Copy link
Collaborator

Closes #2383 , thanks to hint from @jbarlow83 .

try {
msg += pybind11::repr(args_[ti]);
} catch (const error_already_set&) {
msg += pybind11::repr(args_[ti].get_type());
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The repr produced is pretty ugly, but better than a segfault. Maybe should indicate it's an instance of the class?

>       m.simple_bool_passthrough(MyRepr())
E       TypeError: simple_bool_passthrough(): incompatible function arguments. The following argument types are supported:
E           1. (arg0: bool) -> bool
E
E       Invoked with: <class 'test_exceptions.test_invalid_repr.<locals>.MyRepr'>

test_exceptions.py:162: TypeError

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, it should probably say it's an instance.

This is the sort of situation where Python would chain exceptions ("While handling this error, another error occurred..."). but there's no C API for that. Although I wonder if it's worth indicating that an exception occurred in repr().

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It doesn't seem like this information is always available - some compilers are not showing it. Maybe just a "" message would work?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe discard_as_unraisable() does make sense here. It would get the stack trace and exception from __repr__ out, and would not be compiler-dependent.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay, we could use it then; I've added an unchanging <repr raised Error> currently but would be happy to change it.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could potentially put the exception as string into <repr raised str(exc)>, but maybe we'll start some infinite recursion, then?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is a C API for chaining exceptions, see #2112

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What I meant was, for their own reasons, the Python core developers chose to not automate chaining exceptions in C or provide an API to make it easier to do.
https://www.python.org/dev/peps/pep-0490/
It's hard to tell what to make of the situation, in terms of what they think C extensions to do.

We potentially have exceptions for each argument to the function, and each of those could involve an individual chain of exceptions - potentially there's a tree of exceptions. I think chaining these exceptions to each other could muddy the waters because it could end up linking the exceptions from attempts to repr() different arguments. Write unraisable here gets the exception out, and then we print a message complaining that we can't repr() the arguments.

@henryiii henryiii marked this pull request as draft August 14, 2020 16:29
@henryiii
Copy link
Collaborator Author

I currently just have a simple <repr raised Error>, should we do more? It's still better than a segfault. ;)

@YannickJadoul
Copy link
Collaborator

Nah, that's probably fine enough. If this happens, it's because there's a mistake anyway, right? We just don't want stuff to segfault.

@YannickJadoul
Copy link
Collaborator

Is this related to #1716, though?

@henryiii
Copy link
Collaborator Author

I think it would solve that segfault, but the error message would not be as ideal, I'd think?

@YannickJadoul
Copy link
Collaborator

YannickJadoul commented Aug 17, 2020

I think it would solve that segfault, but the error message would not be as ideal, I'd think?

Reading again, it might not be solved, actually? It seems like type_caster for bool leaves the error indicator set in #1716?
EDIT: Apparently I made a PR that should fix it, #1976, but I forgot I did :-D

@wjakob
Copy link
Member

wjakob commented Aug 17, 2020

nice, I vaguely remember running into this in a project of mine, but I never got around to fixing it.

@henryiii
Copy link
Collaborator Author

I think this can go in, then, and the messaging can be improved later if it's needed?

@henryiii henryiii marked this pull request as ready for review August 17, 2020 19:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Segfault when __repr__ throws
5 participants