-
-
Notifications
You must be signed in to change notification settings - Fork 54
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
New caching logic may inadvertently release objects that are still needed #257
Comments
@freakboy3742, I see that you even have left a comment about class-changes happening during initialisation: rubicon-objc/src/rubicon/objc/api.py Lines 785 to 792 in e198bb0
I guess you did not heed your own warning ;) |
Thanks for the report - this one's a doozy. I can reproduce the results you've described with the test code; I haven't been able to reproduce a segfault, but that's going to be unpredictable by definition. Interestingly, in the process of writing #246, I saw cache evictions for Three possible fixes I can think of: Widen the 'stale class name' criteriaInstead of using a strict classname match, we broaden the criteria to identify common renames that don't constitute a an actual stale class. For example, we could use Preserve
|
This is the approach that Chaquopy has always taken, with the intention of making it simply impossible for Python code using the library to cause an invalid pointer access. In practice it's always worked very well, and I'm not aware of it ever causing a memory leak. As I understand it, CPython always calls As mentioned in #256, the main concern would be "cyclic references between Python objects and Objective C objects". I'll have to leave it to those who understand the code better than me to judge how common that would be. |
I've also struggled to reproduce the segfault in a minimal example, but I'm seeing it consistently in full apps. This includes my own, but also toga's Regarding the options which you presented: Widen the 'stale class name' criteriaThis approach would certainly work for the class-name changes that I have observed, but it is hacky because it relies on deducing a rule from a pattern of three. IMO, it makes an already hacky workaround even worse. Gripes that I already have with the current approach:
Preserve
|
Completely agreed that option (1) is a hack stacked on a hack; however, it's also the fastest path forward right now. I've pushed #258 as an implementation of that approach, and a solution to this immediate issue (it seems to fix the |
Describe the bug
The current logic to synchronise object cache access, introduced in #246, may lead to premature releases, because the return values from
alloc()
andinit()
calls will point to the same memory address for the allocated and the initialed object but the class name may have changed between those calls.The code below will then result in the ObjCInstance returned by
alloc()
to be a different Python object than the one returned from the followinginit()
.rubicon-objc/src/rubicon/objc/api.py
Lines 898 to 902 in e198bb0
Because the object returned by
alloc()
is typically not stored in any variable in a chainedalloc().init()
call, it will be garbage collected, leading to arelease()
call from our own__del__
override.rubicon-objc/src/rubicon/objc/api.py
Lines 964 to 970 in e198bb0
Steps to reproduce
Run the following script:
This can in practice lead to segfaults when creating a window early but showing it only later, e.g., on button press.
Expected behavior
We should not send
release()
immediately after aninit()
call, because it will be sent to the same memory address of an object that we still want.Screenshots
No response
Environment
Logs
No response
Additional context
I've observed such class-name changes in particular with
NSWindow
,NSView
andNSApplication
but no other classes so far.The text was updated successfully, but these errors were encountered: