[Interest] Double free in QItemDelegate editor

Kyle Edwards kyle.edwards at kitware.com
Fri Sep 4 21:20:13 CEST 2020


On 9/4/20 2:40 PM, Kyle Edwards wrote:
> After some more investigation, I've learned more about the nature of 
> the problem.
>
> The createEditor() override returns a button which, when clicked, 
> opens a file dialog (through QFileDialog::getOpenFileName() - this 
> will be important in a bit). The opening of this dialog causes the 
> editor to lose focus, which result in QAbstractItemDelegate emitting 
> its closeEditor() signal, which in turn destroys the editor. The 
> destroying of the editor also attempts to delete the file dialog, 
> since it's a child of the editor. However, the file dialog was 
> allocated on the stack by QFileDialog::getOpenFileName(). So, 
> attempting to delete the stack-allocated dialog results in a crash.
>
> So I guess the question is, how do I prevent QAbstractItemDelegate 
> from emitting closeEditor() when the file dialog opens? Either that or 
> prevent closeEditor() from actually closing the editor... I see 
> something in QAbstractItemView::closeEditor() about an editor being 
> "persistent", does that have anything to do with this? 

I now have a minimum working test case:

// BEGIN

#include<QItemDelegate>
#include<QApplication>
#include<QFileDialog>
#include<QLineEdit>
#include<QResizeEvent>
#include<QStandardItemModel>
#include<QToolButton>
#include<QTreeView>
#include<QWidget>
classTestEdit: publicQLineEdit
{
Q_OBJECT
public:
TestEdit(QWidget*parent= nullptr);
voidresizeEvent(QResizeEvent*e) override;
public slots:
voidchooseFile();
private:
QToolButton* toolButton;
};
TestEdit::TestEdit(QWidget*parent)
: QLineEdit(parent)
{
this->toolButton= newQToolButton(this);
this->toolButton->setText("...");
QObject::connect(this->toolButton, SIGNAL(clicked(bool)), this, 
SLOT(chooseFile()));
}
voidTestEdit::resizeEvent(QResizeEvent*e)
{
// make the tool button fit on the right side
inth= e->size().height();
// move the line edit to make room for the tool button
this->setContentsMargins(0, 0, h, 0);
// put the tool button in its place
this->toolButton->resize(h, h);
this->toolButton->move(this->width() - h, 0);
}
voidTestEdit::chooseFile()
{
autopath= QFileDialog::getOpenFileName(this, "title", QString(), QString(),
nullptr, QFileDialog::DontResolveSymlinks);
if(!path.isEmpty()) {
this->setText(path);
}
}
classTestItemDelegate: publicQItemDelegate
{
Q_OBJECT
public:
QWidget*createEditor(QWidget*parent, constQStyleOptionViewItem&option, 
constQModelIndex&index) constoverride;
};
QWidget*TestItemDelegate::createEditor(QWidget*parent, 
constQStyleOptionViewItem&option, constQModelIndex&index) const
{
returnnewTestEdit(parent);
}
intmain(intargc, char**argv)
{
QApplicationapp(argc, argv);
QWidgetwindow;
QTreeViewview(&window);
auto* model= newQStandardItemModel;
view.setModel(model);
model->insertRow(0);
model->insertColumn(0);
model->setData(model->index(0, 0), "Hello");
view.setItemDelegate(newTestItemDelegate);
window.show();
returnapp.exec();
}
#include"qttest.moc"
// END
Run the program, double click the "Hello" item, a line editor will 
appear, click the button on the right to open the dialog, and then the 
invalid delete happens.
Kyle


More information about the Interest mailing list