Closed Kolsky closed 2 years ago
Although it would make sense to clone Rc
Edit: yup, it's not okay at all by a more mundane reason, even. playground (check Miri output). Then if there's no guarantee if callback is still in use at the time it's unbound, there's not much to do other than:
Change in approach, reworking API in a way that would account for this problem (no thoughts yet).
Add a flag indicating the status of callback, if it's running and unbind is requested, then panic or leak. Set the flag before calling and clear after.
Does registration happen to accept function instead of callback? If so, cloning becomes viable since function is an external entity. Panic on full_bind if callback is accessed via static variable and occupied. Would be easier if WindowSubclass allows to store additional data itself.
Oh no... I'll take the time to look into this this week.
Possible fix in #258. Not sure if it makes it completely safe, but it at least seems to fix the crash.
If I understand the issue correctly, when the closure is dropped, it drops BasicApp
, which drops the window handle, which destroys the window, which sends WM_DESTROY
to the window, causing process_events
to be called. Since this happens during the callback drop, the reference count is already 0, so it crashes. I made it remove the subclass before dropping the callback, and that seems to have fixed the problem.
As for @Kolsky's playground example, I don't think it matches nwg exactly. In the example, the Rc is incremented/decremented inside the closure. In nwg, it is incremented/decremented in process_events
, which calls the closure. When I change
(&*FOO)();
to
Arc::increment_strong_count(FOO);
(&*FOO)();
Arc::decrement_strong_count(FOO);
which I believe is closer to how nwg does it, Miri says it's ok.
Can confirm it doesn't crash with #258. If this is the only path to call process_events (no background threads, no issues with event signaling after RemoveWindowSubclass
), then I don't see any other problems. Maybe Window should be non_exhaustive (to privatize constructor) or with private fields, but it's outside the scope of the current issue.
MRE:
Stack trace
nwg_bug.exe!core::cell::CellIntroduced by: #256 (rev. 2c6cf6e)
Definitely not a solution as it stands currently, maybe it should have increased strong count from the get-go which would then be decremented only after for loop inside
unbind_event_handler
completes (just as an example).