Summary
PdmUiFormLayoutObjectEditor destroys QMinimizePanel group boxes with a raw delete. Deleting a parent QWidget destroys its children immediately, so the deleteLater() that PdmUiFieldEditorHandle uses to keep field editor widgets alive never gets a chance to run.
When the rebuild is triggered from fieldChangedByUi(), Qt is still executing an event handler on those widgets further up the stack, giving a use-after-free.
Mechanism
- Tab out of a
PdmUiLineEditor. QLineEdit::focusOutEvent emits editingFinished.
PdmUiLineEditor::slotEditingFinished commits the value, which reaches fieldChangedByUi() and ends in PdmUiItem::updateAllRequiredEditors().
- The property editors are rebuilt. The field editor is deleted, scheduling
deleteLater() on the QLineEdit, and then the parent group box is deleted with a raw delete, destroying that QLineEdit immediately.
- The stack unwinds back into
QLineEdit::focusOutEvent, which continues on freed memory.
The two raw delete sites are in cafPdmUiFormLayoutObjectEditor.cpp:
cleanupBeforeSettingPdmObject() deletes every group box
configureAndUpdateUi() deletes group boxes no longer present in the ui ordering
Both carry a comment referencing #9719, where plain deleteLater() left group boxes behind.
Symptoms vary because the corruption is silent until something reads it. Observed both an access violation inside QLineEdit::focusOutEvent, and a later crash walking the focus chain in QWidget::focusNextPrevChild -> QWidget::setFocus with no caf frames on the stack.
Reproduction
Added to cafTestApplication as ReentrantEditorRebuild. Select the object, type a value into Realization Filter and press Tab. Enter is much less likely to crash, because PdmUiLineEditor::eventFilter calls slotEditingFinished() outside focusOutEvent.
Fix
Hide and detach the group box before scheduling a deferred delete, so it leaves the layout, the visual tree and the focus chain immediately:
groupBox->hide();
groupBox->setParent( nullptr );
groupBox->deleteLater();
Detaching first is what plain deleteLater() did not do, and is intended to also cover #9719.
Related defect
Found while reproducing this: PdmUiLineEditor::configureAndUpdateUi() dereferenced m_autoValueToolButton and m_layout without a null check, unlike m_label and m_lineEdit in the same function. Both are owned by m_placeholder, which is not returned as the editor widget when auto value is not supported and is therefore tracked by nothing. It can be destroyed with a parent widget while the reparented m_lineEdit survives.
Summary
PdmUiFormLayoutObjectEditordestroysQMinimizePanelgroup boxes with a rawdelete. Deleting a parentQWidgetdestroys its children immediately, so thedeleteLater()thatPdmUiFieldEditorHandleuses to keep field editor widgets alive never gets a chance to run.When the rebuild is triggered from
fieldChangedByUi(), Qt is still executing an event handler on those widgets further up the stack, giving a use-after-free.Mechanism
PdmUiLineEditor.QLineEdit::focusOutEventemitseditingFinished.PdmUiLineEditor::slotEditingFinishedcommits the value, which reachesfieldChangedByUi()and ends inPdmUiItem::updateAllRequiredEditors().deleteLater()on theQLineEdit, and then the parent group box is deleted with a rawdelete, destroying thatQLineEditimmediately.QLineEdit::focusOutEvent, which continues on freed memory.The two raw delete sites are in
cafPdmUiFormLayoutObjectEditor.cpp:cleanupBeforeSettingPdmObject()deletes every group boxconfigureAndUpdateUi()deletes group boxes no longer present in the ui orderingBoth carry a comment referencing #9719, where plain
deleteLater()left group boxes behind.Symptoms vary because the corruption is silent until something reads it. Observed both an access violation inside
QLineEdit::focusOutEvent, and a later crash walking the focus chain inQWidget::focusNextPrevChild->QWidget::setFocuswith no caf frames on the stack.Reproduction
Added to
cafTestApplicationasReentrantEditorRebuild. Select the object, type a value into Realization Filter and press Tab. Enter is much less likely to crash, becausePdmUiLineEditor::eventFiltercallsslotEditingFinished()outsidefocusOutEvent.Fix
Hide and detach the group box before scheduling a deferred delete, so it leaves the layout, the visual tree and the focus chain immediately:
Detaching first is what plain
deleteLater()did not do, and is intended to also cover #9719.Related defect
Found while reproducing this:
PdmUiLineEditor::configureAndUpdateUi()dereferencedm_autoValueToolButtonandm_layoutwithout a null check, unlikem_labelandm_lineEditin the same function. Both are owned bym_placeholder, which is not returned as the editor widget when auto value is not supported and is therefore tracked by nothing. It can be destroyed with a parent widget while the reparentedm_lineEditsurvives.