Fix stale event object in GridWithLabelRenderersMixin paint handlers - #2929
Merged
swt2c merged 1 commit intoAug 11, 2026
Merged
Conversation
The three paint handlers (_onPaintRowLabels, _onPaintColLabels,
_onPaintCornerLabel) resolved their target window via
evt.GetEventObject(), even though each handler is bound directly to
one specific label window in __init__ and so already knows which
window it is.
Resolving via GetEventObject() requires SIP to look up the event's
wxObject* in its C++-to-Python object map. That lookup can return a
stale Python wrapper of the wrong type if some unrelated wxObject was
deleted without SIP being notified and a new C++ object was later
allocated at the same freed address. This surfaces as "TypeError:
PaintDC(): argument 1 has unexpected type '<OtherClass>'" raised
repeatedly on every paint of the affected label window, since the
window itself is alive and genuinely painting.
Confirmed at least one concrete source of such stale wrappers: unlike
wx.Frame, wx.MenuBar and wx.Menu, a wx.MenuItem's SIP wrapper is not
marked deleted when the item is destroyed as part of its owning
wxMenuBar's teardown (~wxMenuBase's wxClearList()). Touching the
stale wrapper afterwards dereferences freed memory and segfaults the
process outright, rather than raising a Python exception:
frame.Destroy()
# ... after idle-time deletion runs ...
sip.isdeleted(frame) # True
sip.isdeleted(menuBar) # True
sip.isdeleted(menu) # True
sip.isdeleted(item) # False -- stale, still owned by the deleted menu
item.GetItemLabel() # SIGSEGV
Reported independently at least twice with a different offending type
(SizerItem):
https://discuss.wxpython.org/t/typeerror-when-using-gridwithlabelrenderersmixin/35137
Fix: cache the three label windows in __init__ (the same windows the
handlers are bound to) and use the cached references instead of
evt.GetEventObject().
jmoraleda
force-pushed
the
fix/gridlabelrenderer-stale-event-object
branch
from
July 30, 2026 13:51
9f2a010 to
bdc03b2
Compare
Contributor
Author
|
Filed the underlying stale-wrapper bug that this mixin fix defends against: #2931. Confirmed the same mechanism also affects |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The three paint handlers (_onPaintRowLabels, _onPaintColLabels, _onPaintCornerLabel) resolved their target window via evt.GetEventObject(), even though each handler is bound directly to one specific label window in init and so already knows which window it is.
Resolving via GetEventObject() requires SIP to look up the event's wxObject* in its C++-to-Python object map. If some unrelated, non- window wxObject is deleted without SIP being notified (e.g. a wx.MenuItem freed by ~wxMenuBase, which does not go through SIP's teardown path) and a new C++ object is later allocated at that same freed address, the map lookup can return a stale Python wrapper of the wrong type for the live paint event. This surfaces as "TypeError: PaintDC(): argument 1 has unexpected type ''" raised repeatedly on every paint of the affected label window, since the window itself is alive and genuinely painting.
Reported before at: https://discuss.wxpython.org/t/typeerror-when-using-gridwithlabelrenderersmixin/35137
Fix: cache the three label windows in init (the same windows the handlers are bound to) and use the cached references instead of evt.GetEventObject().