Drag and Drop within wxTreeCtrl on macOS

Hi all,

I’m using Python 3.7.8 and wxPython 4.1.1a1.dev4876… on macOS Catalina and similar (the wxPython is a slightly older daily build) on Windows 10.

I have a TreeCtrl in my program where users can sort items, using drag and drop, into an arbitrary order in the tree that meets their needs. It works great on Windows and crashes reliably on the SECOND data drop on macOS with the error message “zsh: illegal hardware instruction”.

I have attached a simple sample that exhibits the problem. Run the sample and try to sort the items in the tree control. On macOS, you can move one tree item, but not a second one using drag and drop.

The “DragAndDrop” sample in the wxPython Demo does not seem to show this problem, but the “CustomDragAndDrop” sample program also crashes on the second Drop action.

Any feedback is appreciated, as always.

David

DragAndDropMac.py (6.5 KB)

Any chance you can get a stacktrace from the crash?

Hi Scott,

The Crash Report is attached.

  I have also played around a bit with the wxWidgets TreeCtrl

sample. It allows drag-and-drop within the tree, and does NOT
crash on macOS. It’s not an exact duplication of what’s happening
in wxPython, but seems pretty close to me.

David

(Attachment DragDropCrash.rtf is missing)

It says the attachment is missing? Maybe you can’t email attachments?

The crash report attachment was rejected as being the wrong
format. Here’s a second try.

David

DragDropCrash.zip (21.3 KB)

I can reproduce that as well. I don’t really know what might be going on, though. There has been some work on the OSX DND stuff in wxWidgets recently though, so it seems like there could have been a regression there. I’d suggest opening a wxWidget bug.

Thanks for the confirmation Scott. I could not reproduce the
issue with the existing wxWidgets TreeCtrl example, but I will try
to modify it to make it closer to the wxPython sample I’ve
created. Their sample copied nodes rather than moving (deleting
and recreating) them.

David

The sample also doesn’t use wxCustomDataObject either - that could be relevant?

Scott,

  Turns out that IS relevant.  I rewrote my sample to use a

TextDataObject rather than a CustomDataObject, and it does not
crash any more on macOS. (I also added the distinction between
copying and moving, and the CustomDataObject version crashes on
copies as well as moves.)

  My application needs a CustomDataObject to pass the information I

need to pass. I don’t immediately see a way around it, at least
not one that doesn’t feel like a hack.

  I have doubts about my ability to write a C example using a

CustomDataObject, but I guess that’s where I’m headed next. Wish
me luck.

David

I have tried your example on MacOS High Sierra (10.13.6) with wxPython 4.0.7.post2 / wxWidgets 3.1.3 on Python 3.8.3 and it does not crash. The items move as they should.

Pieter, that suggests recent changes are the cause.
Unfortunately, I need a couple of fixes that are in the latest
daily build for my application.

I’ve attached a new sample program.

  If you change Line 1, you can switch between using the

CustomDataObject and the TextDataObject. The CustomDataObject
version crashes, while the TextDataObject version doesn’t on macOS
on the second drag-and-drop operation.

  This version allows both Copy and Move.  Makes no difference. 

They both crash on the second drop operation on the Mac.

  If you use the menu's Cut / Copy / Paste options instead of

drag-and-drop, the program does not crash, even when
CustomDataObject is being used.

  Finally, I added print() statements around the DoDragDrop()

method. This shows that this method does complete itself prior to
the program crashing. If I understand things correctly, that
means that the drag and drop operation is complete when the crash
occurs.

  Given all of that, it seems to me that there is an interaction

between CustomDataObject and Drag-and-Drop processing that shows
itself during the final clean-up stages. CustomDataObject works
okay through the clipboard. Drag-and-drop works okay with the
TextDataObject. When the two are used together, everything
crashes after the operation is complete, like it’s happening
during object clean-up and destruction. Does that all sound
reasonable?

  I am not able to write a C-based wxWidgets sample for this

program. I can’t figure out the subtleties of drag-and-drop in C
at this point. I’ll raise the issue on the wxWidgets discussion
board, but I have little hope that will have any effect without a
sample program.

Thanks for your help getting this issue figured out,

David

DragAndDropMacCDO.py (8.48 KB)

You might be able to get help even with providing a Python sample program.

I’ll try to dig into this over the weekend.

See also:

I think I’ve finally made some progress on this, at least to the point of having a workaround I can recommend. The crashes seem to be related to the wx.DataFormat object and so my first thought was that it is yet another ownership transfer issue like what we’ve had to deal with before. But since it only happens when using a format type id string, and only on OSX, then I suspect instead that it may be an issue in wxMac.

The Mac wxDataFormat class has a wx-wrapped CFString member, which is reference counted and managed by the system IIRC. Some of the crashes I observed pointed to the code where that is destroyed. I’m not sure yet why it isn’t a problem from C++, but my speculation is that there is some difference in timing as to when the data format object is being destroyed, and that could be causing that CFString to be gc’d early, causing a double delete when it is later destroyed when the Python data format object is cleaned up. Or something like that. I’m still digging.

Anyway, back to the workaround. I found that if your custom wx.DataFormat object is a global, that you create only once and reuse each time you need it, then the crash is avoided. At least in my test cases. Give the nature of the workaround it’s possible that there could still be an issue when that global data format object is cleaned up, but so far I have not run into that.

Oh, it looks like there is already a way to reproduce this bug in the C++ dnd sample. I’m glad I found that before adding my own code to it! Anyway, it is now in the hands of the C++ devs.

Excellent news. Thanks for following up on this and for the
potential work-around.

David

The next snapshot build should include the wxMac fix. For those who are interested in the details the commit implementing the fix is here: