I recently ran into very sporadic and hard to reproduce hangs and
segfaults (installing faulthandler sometimes prints "GC object already
tracked") with an application that runs fine with wxPython classic 3.0.2
(Win10 64-bit, Python 2.7 32-bit). After lots of poking, I tracked it
down to the OnPaint handler of wx.lib.gradientbutton.GradientButton,
more specifically, the call to gc.GetTextExtent therein (other stuff
that calls gc.GetTextExtent is affected as well). The hang/segfault can
be avoided by replacing GraphicsContext.GetTextExtent calls with
self.GetTextExtent, or using wxPython Classic instead.
I've since tried to come up with a reproducible test case, which turned
out to be challenging due to the even more sporadic nature of the
problem when isolated, but have hopefully succeeded.
Condition: For the hang/segfault to happen, there need to be calls to
GraphicsContext.GetTextExtent in the UI thread, and there needs to be a
background thread
that actually does something, even if it is just sleep()-ing, and
creates some load. The more happens in the background thread, the more
likely the problem occurs.
The attached script, when run without arguments for a while (say, a
minute), should reproducibly hang after closing the main window when
using wxPython 4.0.0a1/a2 and Python 2.7 32-bit under Windows (10 in my
case, but I would assume the Windows version doesn't really matter, and
probably also the Python version). I have not tested under other systems.
You can run the script with the argument `wxbutton` to prevent the hang,
which will make it use wx.Button instead of GradientButton, or with the
argument `fix` to override GraphicsContext.GetTextExtent.
Some notes:
DO NOT run this test on a single core machine. It will bog down the system.
To make the hang/segfault more likely, the number of elements
dynamically calling GraphicsContext.GetTextExtent is increased far
beyond reasonable limits
and split across several dialogs with timers that change the state and
visual appearance of the elements in periodic intervals, to increase the
amount of GraphicsContext.GetTextExtent calls.
I would assume this will need fixing in the wxPython C++ codebase.
wx40a2_GC_GetTextExtent_hang_on_exit.py (5.71 KB)
···
--
Florian Höch