Сбой QtPropertyBrowser/QTreeModel при очистке

последние несколько дней я пытаюсь решить этот странный сбой, который происходит только в OS X 10.10. Я немного изменил QtTreePropertyBrowser с кнопками внутри строк свойств:


(источник: inventic.eu)

Эти кнопки излучают сигналы при нажатии, а некоторые действия приводили к очистке дерева и его повторному перестроению. К сожалению, это приводит к сбою.

Я думал, что это из-за очистки дерева внутри обработки сигнала, но постановка его в очередь через QEvent не помогает. Проблема в том, что сбой иногда происходит через некоторое время после очистки дерева.

Все сбои заканчиваются одним из этих двух стеков вызовов:

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:] + 

Код сбоя выглядит следующим образом:


(источник: inventic.eu)

и

Основываясь на коде, мне кажется, что это ошибка в TreeModel, когда некоторые индексы не очищаются после стирания модели дерева. К сожалению, я не являюсь родным разработчиком Mac (но Windows), и я не могу полностью понять, что происходит с индексами из-за не полностью работающего отладчика в QtCreator. Но, судя по сбою, кажется, что в обоих случаях item не является допустимым указателем.

Что иногда помогает, так это установить фокус на другой виджет перед очисткой дерева свойств (как я описал здесь). Но это исправление работает не всегда, и иногда приложение все равно падает.

Я уже извлек весь код из основного приложения и создал минимальный тестовый пример. Я пробовал много вещей, но безуспешно.

Что не работает:

  • деактивировать фокус из окна перед очисткой
  • выполнить очистку вне обработки сигнала, создав QEvent с действием
  • для очистки дерева свойств один за другим вместо метода clear()
  • перекомпилировать тестовый проект с последней бета-версией Qt 5.5
  • чтобы скомпилировать приложение на более старой OS X (10.9) и выполнить его на 10.10

Что работает:

  • компилировать тот же код на Windows/Linux
  • для выполнения того же кода на более старой OS X

Вот пример сбоя приложения: https://dl.dropboxusercontent.com/u/11355235/ShareX/2015-05/2015-05-21_15-28-56.mp4

Самый простой способ выполнить эту ошибку — очистить дерево свойств и открыть любой диалог (который выполняет цикл событий, который, вероятно, вызывает сбой)

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

Минимальное тестовое приложение доступно здесь: https://www.dropbox.com/s/dbnd3inbwpfc6l9/property-tree-crash.zip?dl=0

Буду рад любым идеям или помощи в решении этой проблемы (платная помощь тоже, если она здесь разрешена). Пожалуйста, дайте мне знать, если потребуется дополнительная информация.


person Ludek Vodicka    schedule 21.05.2015    source источник
comment
Вы хотите, чтобы мы отлаживали через файл mp4? Там нет SSCCE, бесполезные скриншоты. Голосуйте за закрытие...   -  person Dmitry Sazonov    schedule 21.05.2015
comment
Три вещи: (1) скриншоты не относятся к коду, где он гудит, стек вызовов говорит вам, где он находится, (2) вы пытались запустить на нем valgrind, чтобы увидеть, сообщает ли он о каких-либо операциях записи/чтения в память, которые должны Если это не происходит, (3) пробовали ли вы явно использовать соединение с очередями, а не прямое соединение сигнал/слот, чтобы выяснить, имеет ли значение порядок событий?   -  person user268396    schedule 21.05.2015
comment
Я думаю, что функция item(index); возвращает недействительный указатель на QTreeWidgetItem. Проверь это.   -  person vahancho    schedule 21.05.2015
comment
Добавление (1) имеет значение, потому что трассировка стека говорит вам, куда он идет, а код на скриншоте - это не то место. (2) имеет значение, потому что проблема звучит так, как будто иногда вы segfault, а иногда вы хромаете, только что прочитав/записав доступную память, которой вы владеете, но не должны были касаться. (3) имеет значение, потому что прямые соединения — это вызовы методов, а очистка модели и последующее выполнение действий над старой моделью — это, очевидно, путь к катастрофе.   -  person user268396    schedule 21.05.2015
comment
@ user268396 1) Я добавил скриншот места падения. К сожалению, нет ничего полезного, это только геттер. Из-за этого я добавил скриншот с предыдущего уровня   -  person Ludek Vodicka    schedule 21.05.2015
comment
@ user268396 2) пока нет, потому что у меня нет такого опыта работы с Valgrind (я основной разработчик Windows), но я попробую. 3) Уже пробовал. Вместе с проверкой того, не создается ли одно и то же событие дважды: i.imgur.com/5XFXwUk.png   -  person Ludek Vodicka    schedule 21.05.2015
comment
@ vahancho: Да, я тоже так думаю. К сожалению, я не могу понять, почему. Весь стек вызовов поступает из функций OSX без какой-либо полезной информации.   -  person Ludek Vodicka    schedule 21.05.2015
comment
@ user268396: Определенно согласен со всеми 1) 2) 3). Из-за этого я попытался сериализовать эти события через QEvent (и QTimer тоже). Это определенно что-то с недопустимым доступом к памяти. Под соединением в очереди вы подразумеваете QApp::postEvent или есть какой-то другой способ?   -  person Ludek Vodicka    schedule 21.05.2015
comment
@SaZ Краткий пример доступен в файле dropbox. Я попытался максимально подробно описать и свести к минимуму проблему, но, поскольку это целый компонент QtPropertyTree, это непростая задача. Файл MP4 показывает, как и где происходит сбой приложения.   -  person Ludek Vodicka    schedule 21.05.2015
comment
И еще одно замечание. Приложение работает правильно (а также все индексы/указатели верны) в Windows/Linux, поэтому, вероятно, проблема в реализации метода clear() в Mac OSX.   -  person Ludek Vodicka    schedule 21.05.2015
comment
@LudekVodicka, когда вы подключаете сигнал к слоту, вы можете дополнительно указать режим. По умолчанию используется прямое соединение (примерно эквивалентное вызову метода в точке отправки), если оба объекта имеют одинаковую привязку к потоку; соединение в очереди ставит в очередь событие в цикле обработки событий для последующей обработки (это также правильный способ для соединений, которые пересекают границы потоков).   -  person user268396    schedule 23.05.2015


Ответы (1)


Вся проблема заключалась в реализации Qt Accessibility на OS X.

Когда активный элемент в дереве проекта изменяется, также обновляется QAccessibleTableCell, к сожалению, когда активный элемент отменяется (индекс недействителен), QAccessibleTableCell не обновляется.

Благодаря этой очистке дерево свойств вызывало сбой, поскольку QAccessibleTableCell пытался получить доступ к неверным данным.

Я написал более подробное описание в моем блоге.

person Ludek Vodicka    schedule 25.05.2015