Last week I was having a pretty serious problem with wxPython on the Macintosh. The following block of code in wxPython is just plain wrong and after a few hours of operations the m_waiters array would be corrupted because of multiple threads contending for the memory.
If you're running wxPython 2.5.1.5, seriously considering patching your library as per these instructions.
while ( m_owner != kNoThreadID && m_owner != current)
{
m_waiters.Add(current);
::SetThreadStateEndCritical(kCurrentThreadID, kStoppedThreadState, m_owner);
::ThreadBeginCritical();
}
It should read (as far as I can tell)
while ( m_owner != kNoThreadID && m_owner != current)
{
::SetThreadStateEndCritical(kCurrentThreadID, kStoppedThreadState, m_owner);
m_waiters.Add(current);
::ThreadBeginCritical();
}
I knew that rebuilding wxPython libraries from scratch could end up being more trouble than it's worth, so I decided to take a different approach. Last Friday night I did an extending hacking session on wxPython's libraries. I downloaded Apple's Xcode developer tools and disassembled (using objdump) the broken module. Looking at the PowerPC opcodes, I figured one little tweak would do the trick. I needed to change this:
675f8: 38 a0 00 01 li r5,1
675fc: 4b fb 17 39 bl [wxBaseArrayLong::Add]
67600: 38 60 00 01 li r3,1
67604: 38 80 00 01 li r4,1
67608: 80 be 00 00 lwz r5,0(r30)
6760c: 48 01 30 69 bl [::SetThreadStateEndCritical]
67610: 48 01 30 a5 bl [::ThreadBeginCritical]
to this:
67610: 48 01 30 a5 bl [::ThreadBeginCritical]
675f8: 38 a0 00 01 li r5,1
675fc: 4b fb 17 39 bl [wxBaseArrayLong::Add]
67600: 38 60 00 01 li r3,1
67604: 38 80 00 01 li r4,1
67608: 80 be 00 00 lwz r5,0(r30)
6760c: 48 01 30 69 bl [::SetThreadStateEndCritical]
Note that I had to figure out those symbolic names — the objdump program didn't do that for me. Here's a Python program to make the fix:
old_data = [ 0x38, 0xa0, 0x00, 0x01, 0x4b, 0xfb, 0x17, 0x39, # wxArrayLong::Add 0x38, 0x60, 0x00, 0x01, 0x38, 0x80, 0x00, 0x01, 0x80, 0xbe, 0x00, 0x00, 0x48, 0x01, 0x30, 0x69, # ::SetThreadStateEndCritical 0x48, 0x01, 0x30, 0xa5, # ::ThreadBeginCritical ] new_data = [ 0x48, 0x01, 0x30, 0xa5, # ::ThreadBeginCritical 0x38, 0xa0, 0x00, 0x01, 0x4b, 0xfb, 0x17, 0x39, # wxArrayLong::Add 0x38, 0x60, 0x00, 0x01, 0x38, 0x80, 0x00, 0x01, 0x80, 0xbe, 0x00, 0x00, 0x48, 0x01, 0x30, 0x69, # ::SetThreadStateEndCritical ] fio = open('build/Jaeger.app/Contents/Frameworks/libwx_base_carbond-2.5.1.0.0.dylib', 'rb+') fio.seek(start) f_in = fio.read(len(old_data)) for i in xrange(len(old_data)): if old_data[i] != ord(f_in[i]): print >> sys.stderr, "data did not match" print >> sys.stderr, "%d: %02x %02x" % ( i, old_data[i], ord(f_in[i]) ) sys.exit(1) fio.seek(start) for i in xrange(len(new_data)): fio.write(chr(new_data[i])) fio.close()
There was one other piece of code causing a crash in Jäger. My advice — never never ever try to modify wxPython objects from outside their thread: it ain't ever going to work.

