-
Notifications
You must be signed in to change notification settings - Fork 2.2k
[BUG]: Recursive dispatch fails to find python function override. #3357
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
Comments
Here is the commit that introduced it: f5c154a |
Update: We do have a unit test for it: pybind11/tests/test_virtual_functions.py Line 239 in e08a581
|
@Skylion007 Thanks for the pointers! It looks like this commit fixes the issue of similar names in two different classes. However, the code did return an empty function object when invoked from the method within the same object even prior to this commit. What would be the reason to return an empty function if the caller has the same caller name? Effectively, why the recursion in the |
After some digging, I discovered that adding just one extra frame to CPython call stack solves the problem. For example, the following indirect call to visitor makes the examples above work! class Adder(module.Adder):
def __call__(self, first, second, visitor):
(lambda : visitor(Data(first.value + second.value)))() Now, the question is, is it possible to add a new stack frame to the current CPython thread, when binding to Apologies, I'm not too familiar with CPython API to be able to figure it out myself and submit a patch. |
That's an interesting clue. I'm not sure when we will have a volunteer to work on fixing this. Pragmatic suggestion:
Then at least we have an easy starting point for someone to pick up debugging and fixing. (BTW: is the "pthin" a typo? Would be good to fix, or explain, or maybe you mean "Python thin" and you could just spell it out?) P.S.: Please tag me on the PR, I'll then look quickly. |
@rwgk Thank you for suggestion! I'll do that, and hopefully it'll be a good guide for fixing the issue. |
@wjakob Do you know why this code snippit is necessary and how we can restrict this check to handle this edge case? |
"IRC this was to address a serious bug (infinite recursion -> stack overflow) that could occur when those extra checks were removed. There wasn’t a straightforward way to fix this without massively changing the implementation." from @wjakob |
There is a related dispatch issue preventing full 3.11 support in #3419, we may need to rework this code section. |
Required prerequisites
Problem description
Consider a simple C++ visitor pattern:
In this pattern, Data and Adder are abstract classes which can be used in two algorithms
add
andadd3
which, as the name suggest, add two or three objects of the typeData
and send the result to a visitor. This pattern is intended to eliminate allocating memory for Data pointer in case we need to store temporary results, e.g., seeadd3
algorithm.Next, we define the corresponding python bindings:
Finally, let's test it in Python. Firs,t some boilerplate:
Testing function
add
yields the expected resultHowever, testing
add3
causes failureThe error reads
Chaising the problem through
pybind11
sources, I found a possible culprit. In functionget_type_override
, we check if dispatch code is invoked from overridden function.It returns an empty function if the second override is called from the same frame as the first override. Commenting this check renders a working example. I consider this as a bug, but please let consider proving me wrong.
My questions are:
The link for reproducible and extended examples: https://bitbucket.org/yershov/recursive-dispatch/src/main/
Reproducible example code
The text was updated successfully, but these errors were encountered: