0

last few days I'm trying to solve this strange crash which occurs only on OS X 10.10. I have slightly modified QtTreePropertyBrowser with buttons inside the property rows:


(source: inventic.eu)

These buttons emits signals when clicked and some actions caused clearing the tree and rebuilding it again. Unfortunately this causes the crash.

I thought it is because of clearing tree inside the signal processing but queuing it via QEvent doesn't help. The problem is that crash sometimes occurs also some time after the tree is cleared up.

All crashes end with one of these two callstacks:

QTreeModel::index(QTreeWidgetItem const*, int) const + 176
QTreeModel::parent(QModelIndex const&) const + 75
QTreeView::isIndexHidden(QModelIndex const&) const + 71
QTreeView::visualRect(QModelIndex const&) const + 93
QAccessibleTableCell::rect() const + 29
QAccessibleTableCell::state() const + 146
QCocoaAccessible::hasValueAttribute(QAccessibleInterface*) + 58
[QMacAccessibilityElement accessibilityAttributeNames] + 398
NSAccessibilityEntryPointAttributeNames + 115
[NSObject(NSAccessibilityInternal) _accessibilityAttributeNamesClientError:] + 56

or

QTreeModel::data(QModelIndex const&, int) const + 46
QAccessibleTableCell::state() const + 347
QCocoaAccessible::hasValueAttribute(QAccessibleInterface*) + 58
[QMacAccessibilityElement accessibilityAttributeNames] + 398
NSAccessibilityEntryPointAttributeNames + 115
[NSObject(NSAccessibilityInternal) _accessibilityAttributeNamesClientError:] + 

Crash code looks like following:


(source: inventic.eu)

and

Based on the code it seems to me as bug in TreeModel where some indexes aren't cleared up after tree model is erased. Unfortunately I'm not native Mac developer (but Windows) and I'm not able to fully understand what is going wrong with indexes because of not fully working debugger in QtCreator. But based on the crash it seems that in both cases item isn't a valid pointer.

What sometimes helps is to set focus to different widget before clearing up the property tree (as I described here). But this fix doesn't work always and sometimes application still crashes.

I already extracted all code from the main application and created the minimal test case. I tried a lot of things but without success.

What is not working:

  • to deactivate focus from window before clearing
  • to execute clear outside the signal processing via creating QEvent with action
  • to clear property tree one-by-one instead of clear() method
  • to recompile test project with latest Qt 5.5 beta
  • to compile the app on older OS X (10.9) and execute it on 10.10

What is working:

  • to compile the same code on Windows / Linux
  • to execute the same code on older OS X

Here is an example how application crashes: https://dl.dropboxusercontent.com/u/11355235/ShareX/2015-05/2015-05-21_15-28-56.mp4

The simplest way how to execute this bug is to clear the property tree and open any dialog (which executes the event loop which probably triggers the crash)

on_btnStandaloneDialog_clicked();
m_propertyBrowser->clear();
on_btnStandaloneDialog_clicked();

Minimal test case application is available here: https://www.dropbox.com/s/dbnd3inbwpfc6l9/property-tree-crash.zip?dl=0

I will be glad for any ideas or help with this problem (paid help too if it's allowed here). Please let me know if more information will be required.

Community
  • 1
  • 1
Ludek Vodicka
  • 1,610
  • 1
  • 18
  • 33
  • You want us to debug via mp4 file? No SSCCE there, useless screenshots. Vote to close... – Dmitry Sazonov May 21 '15 at 13:51
  • Three things: (1) screenshots are not of the code where it goes "boom", the call stack tells you where that is, (2) have you tried running valgrind on it to see if it reports any write/reads to memory that shouldn't be happening, (3) have you tried explicitly using a queued connection as opposed to direct signal/slot connection to suss out whether or not ordering of events matters? – user268396 May 21 '15 at 13:59
  • 1
    I think the `item(index);` function returns an invalidated pointer to `QTreeWidgetItem`. Check that out. – vahancho May 21 '15 at 14:01
  • To add (1) matters because the stack trace tells you where it goes boom, and the screencapped code isn't that place. (2) matters because the issue sounds like sometimes you segfault and sometimes you limp on having just read/written to accessible memory you own but shouldn't have touched. (3) matters because direct connections are method calls, and clearing a model and then performing actions on old model stuff is obviously a recipe for disaster. – user268396 May 21 '15 at 14:01
  • @ user268396 1) I added screenshot of crash location. Unfortunately there isn't anything usefull, it's getter only. Because of that I added screenshot from previous level – Ludek Vodicka May 21 '15 at 14:23
  • @ user268396 2) not yet because I don't have such experiences with Valgrind ( I'm primary Windows developer), but I will try it. 3) Already tried it. Together with checking whether the same event isn't created twice: http://i.imgur.com/5XFXwUk.png – Ludek Vodicka May 21 '15 at 14:27
  • @ vahancho: Yes, this is what I think too. Unfortunately I'm not able to figured out why. Whole callstack comes from OSX functions without any usefull info – Ludek Vodicka May 21 '15 at 14:28
  • @user268396: Definitely agree with all 1) 2) 3). Because of that I tried to serialize these events via QEvent (and QTimer too). It's definitely something with invalid access to memory. By "queued connection" do you mean QApp::postEvent or there is any other way? – Ludek Vodicka May 21 '15 at 14:32
  • @SaZ Short example is available in dropbox file. I tried to describe and minimize the problem as much as possible but because it's a whole QtPropertyTree component this isn't an easy task. The MP4 file is there to show how and where the app crashes. – Ludek Vodicka May 21 '15 at 14:34
  • And one more note. The application works correctly (and also all indexes/pointers are correct) on Windows / Linux so it's probably some problem with Mac OSX implementation of clear() method. – Ludek Vodicka May 21 '15 at 14:43
  • @LudekVodicka when you connect a signal to a slot you can optionally specify the "mode". The default is a direct connection (roughly equivalent to a method call at point of emit) if both objects have the same thread affinity; a queued connection will queue an event on the eventloop for later processing (is also the correct way for connections that cross thread boundaries). – user268396 May 23 '15 at 18:59

1 Answers1

0

The whole problem was in Qt Accessibility implementation on OS X.

When active element on project tree is changed, also QAccessibleTableCell is updated, unfortunately when active element is deselected (index is not valid), QAccessibleTableCell isn't updated.

Thanks to this clearing the property tree was causing the crash because QAccessibleTableCell was trying to access invalid data.

I wrote more detailed description on my blog.

Ludek Vodicka
  • 1,610
  • 1
  • 18
  • 33