-
Notifications
You must be signed in to change notification settings - Fork 41
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
Keeping Parent Structures Alive While Substructures Are #141
Comments
It can be tricky to manage object lifetimes when one mixes C and Python like CFFI allows you to do.
You must explicitly keep the return value alive, otherwise the GC will destroy it. Making it explicit may be clearer, and suggests a path to solving the problem. I think this would solve the problem, does it make sense?
|
Thank you for your quick answer! I was assuming that Then, I have another question regarding the fix you proposed, just to be sure: Until when is |
@mattip I think you're going in the wrong direction. The C code doesn't call |
@mattip Sorry, now I understood why your proposed fix is correct. Another way to view it is by changing the prints:
You can see that the first time it is called, it is with a |
@nhusung Python semantics should guarantee that But that's arguably an unclean workaround for a bug of cffi. Maybe cffi itself should keep the parent structure alive when we get a substructure. There isn't much of a point about getting a substructure, which is really a pointer somewhere inside the parent structure, if we don't keep the parent alive. |
There must be previous art for this kind of problem. CTypes or C/C++? |
convert_from_object()
for Structs(?)
Ctypes uses very extensive keepalive rules that cffi was never meant to
copy. C doesn't have any keepalive. C++ doesn't natively have any but
some frameworks give you some. Cffi does a few special cases but defaults
to "no".
Maybe it's possible to come up with a rule that generalize the few existing
rules. Something like: if you start with an "owning" object and do ANY
basic operation that returns a pointer inside the SAME "owned" structure or
array, maybe that returned pointer object should always inherit the
keepalive.
|
I’m not sure whether this is a CFFI or a CPython bug, but recently this issue was reported: OxiDD/oxidd#23. Today, I created a stripped-down version of the CFFI-based bindings at https://github.com/nhusung/cffi-cpython-bug. On the C side, we have some handle type
handle_t
, which is a pair of a pointer and an index. Conceptually, these handles refer to binary nodes, but in the example I just use arbitrary values. The C functionhandle_pair_t children(handle_t)
should just return the handles to the two “child nodes” as a pair, but the bindings appear to modify the Python object corresponding to the handle passed as argument tochildren()
. (Note that the C function takes the handle by value, so it cannot be the culprit.) Here is the Python test code:Output (the line between “before” and “after” is from the C code):
I could reproduce this with CFFI 1.17.1 on both CPython 3.10.12 (Ubuntu 22.04) and CPython 3.12.7 (Fedora 40). PyPy does not appear to be affected (tested with PyPy 7.3.15 / Python 3.10.13).
With GCC’s address sanitizer, I get the following error message directly after
before: (<cdata 'void *' 0x7efec7aa0760>, 21)
:The text was updated successfully, but these errors were encountered: