PDA

View Full Version : Unexplained Segmentation Fault with QDialog::show() and QDialog::exec()



powerofpi
25th February 2011, 22:29
In a Qt 4.7.1 project in Ubuntu 10.10 x64, I have subclassed QDialog and am calling it in the following way:



//Create a dialog window to get the requested difficulty
this->generateNewDialog = new GenerateNewDialog(this);
connect(this->generateNewDialog, SIGNAL(difficultySelected(int)), this, SLOT(generationDifficultySelected(int)));

this->generateNewDialog->exec();


Without fail, this always produces a segmentation fault and crashes my program on the exec() call (not before). Looking at the call stack, the fault occurs at:

QWidgetPrivate::create_sys
QWidget::create
QWidget::setVisible
QDialog::setVisible
show
QDialog::exec

Does anyone see a reason for the behavior? I don't.

mcosta
25th February 2011, 23:05
Can you post the code for GenerateNewDialog?

powerofpi
25th February 2011, 23:12
header file


#ifndef GENERATENEWDIALOG_H
#define GENERATENEWDIALOG_H

#include <QDialog>
#include <QSpinBox>
#include <QDialogButtonBox>
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QLabel>
#include <QSpinBox>
#include <QPushButton>
#include <QDebug>
class GenerateNewDialog : public QDialog
{
Q_OBJECT
private:
void setupInterface();
void setupActions();
QVBoxLayout * m_mainLayout;
QHBoxLayout * m_firstSetting;
QLabel * m_label1;
QSpinBox * m_difficultyPicker;
QPushButton * m_cancel, * m_start;
QDialogButtonBox *buttonBox;
int m_difficulty;
public:
explicit GenerateNewDialog(QWidget *parent = 0);
virtual ~GenerateNewDialog();
signals:
void difficultySelected(int difficulty);
private slots:
void accept();
void reject();
public slots:

};

#endif // GENERATENEWDIALOG_H


class file


#include "generatenewdialog.h"

GenerateNewDialog::GenerateNewDialog(QWidget *parent) :
QDialog(parent, Qt::Sheet)
{
setupInterface();
setupActions();
}
//----------------------------------------------------------------------------
// Constructor & destructor.

GenerateNewDialog::~GenerateNewDialog(void) {
// Is automatically deleted, because it's a child of of the main widget.
//delete m_mainLayout;
delete m_firstSetting;
delete m_label1;
delete m_difficultyPicker;
delete m_cancel;
delete m_start;
}


//----------------------------------------------------------------------------
// Private slots.

/**
* The dialog was accepted. Emit the newGame() signal.
*/
void GenerateNewDialog::accept(void) {
m_difficulty = m_difficultyPicker->value();

close();

emit difficultySelected(m_difficulty);
}


//----------------------------------------------------------------------------
// Private methods.

/**
* Create the UI.
*/
void GenerateNewDialog::setupInterface(void) {
setContextMenuPolicy(Qt::NoContextMenu);
setModal(true);

// Configure layouts.
m_mainLayout = new QVBoxLayout(this);
m_firstSetting = new QHBoxLayout();
m_mainLayout->addLayout(m_firstSetting);

// Set up the buttons.
this->buttonBox = new QDialogButtonBox(this);
this->buttonBox->setOrientation(Qt::Horizontal);
m_cancel = new QPushButton(tr("&Cancel"));
this->buttonBox->addButton(m_cancel, QDialogButtonBox::RejectRole);
m_start = new QPushButton(tr("&Start!"));
m_start->setDefault(true);
this->buttonBox->addButton(m_start, QDialogButtonBox::AcceptRole);
m_mainLayout->addWidget(buttonBox);

// Difficulty label.
m_label1 = new QLabel(this);
m_label1->setText(tr("Difficulty level"));
m_firstSetting->addWidget(m_label1);
m_firstSetting->setAlignment(m_label1, Qt::AlignLeft);

// Difficulty spinbox.
m_difficultyPicker = new QSpinBox(this);
m_difficultyPicker->setMinimum(1);
m_difficultyPicker->setMaximum(5);
m_difficultyPicker->setSingleStep(1);
m_difficultyPicker->setValue(1);
m_firstSetting->addWidget(m_difficultyPicker);
m_firstSetting->setAlignment(m_difficultyPicker, Qt::AlignRight);

// Connect the signals from the buttonbox to the GenerateNewDialog.
connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept()));
connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject()));
}
void GenerateNewDialog::setupActions(){
// Connect the signals from the buttonbox to the NewGameDialog.
connect(this->buttonBox, SIGNAL(accepted()), this, SLOT(accept()));
connect(this->buttonBox, SIGNAL(rejected()), this, SLOT(reject()));
}

void GenerateNewDialog::reject(){
qDebug() << "GenerateNewDialog received reject signal.";
close();
}

mcosta
25th February 2011, 23:37
There are many strange things!

1) In the destructor you delete the children created in setupInterface();

2) you connect twice accepted and rejected signals to slots;

3) You emit signal on accept(), should be simpler to read property in calling code after exec returns.

powerofpi
25th February 2011, 23:46
Thank you for your ideas.

1) & 4) The reason I emit a signal on accept() is because I need to get the index of the spinbox that was selected. If there's a better way to do this, let me know!

2) Why would this be a bad thing? I need to free the memory before the dialog ceases to exist, right?

3) Yes, that was just a mistake.

Revised code that still produces a seg fault:


#ifndef GENERATENEWDIALOG_H
#define GENERATENEWDIALOG_H

#include <QDialog>
#include <QSpinBox>
#include <QDialogButtonBox>
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QLabel>
#include <QSpinBox>
#include <QPushButton>
#include <QDebug>
class GenerateNewDialog : public QDialog
{
Q_OBJECT
private:
void setupInterface();
void setupActions();
QVBoxLayout * m_mainLayout;
QHBoxLayout * m_firstSetting;
QLabel * m_label1;
QSpinBox * m_difficultyPicker;
QPushButton * m_cancel, * m_start;
QDialogButtonBox *buttonBox;
int m_difficulty;
public:
explicit GenerateNewDialog(QWidget *parent = 0);
virtual ~GenerateNewDialog();
signals:
void difficultySelected(int difficulty);
private slots:
virtual void accept();
virtual void reject();
public slots:

};

#endif // GENERATENEWDIALOG_H



#include "generatenewdialog.h"

GenerateNewDialog::GenerateNewDialog(QWidget *parent) :
QDialog(parent, Qt::Sheet)
{
setupInterface();
setupActions();
}
//----------------------------------------------------------------------------
// Constructor & destructor.

GenerateNewDialog::~GenerateNewDialog(void) {
// Is automatically deleted, because it's a child of of the main widget.
//delete m_mainLayout;
delete m_firstSetting;
delete m_label1;
delete m_difficultyPicker;
delete m_cancel;
delete m_start;
}


//----------------------------------------------------------------------------
// Private slots.

/**
* The dialog was accepted. Emit the newGame() signal.
*/
void GenerateNewDialog::accept(void) {
m_difficulty = m_difficultyPicker->value();

emit difficultySelected(m_difficulty);
QDialog::accept();
}


//----------------------------------------------------------------------------
// Private methods.

/**
* Create the UI.
*/
void GenerateNewDialog::setupInterface(void) {
setContextMenuPolicy(Qt::NoContextMenu);
setModal(true);

// Configure layouts.
m_mainLayout = new QVBoxLayout(this);
m_firstSetting = new QHBoxLayout();
m_mainLayout->addLayout(m_firstSetting);

// Set up the buttons.
this->buttonBox = new QDialogButtonBox(this);
this->buttonBox->setOrientation(Qt::Horizontal);
m_cancel = new QPushButton(tr("&Cancel"));
this->buttonBox->addButton(m_cancel, QDialogButtonBox::RejectRole);
m_start = new QPushButton(tr("&Start!"));
m_start->setDefault(true);
this->buttonBox->addButton(m_start, QDialogButtonBox::AcceptRole);
m_mainLayout->addWidget(buttonBox);

// Difficulty label.
m_label1 = new QLabel(this);
m_label1->setText(tr("Difficulty level"));
m_firstSetting->addWidget(m_label1);
m_firstSetting->setAlignment(m_label1, Qt::AlignLeft);

// Difficulty spinbox.
m_difficultyPicker = new QSpinBox(this);
m_difficultyPicker->setMinimum(1);
m_difficultyPicker->setMaximum(5);
m_difficultyPicker->setSingleStep(1);
m_difficultyPicker->setValue(1);
m_firstSetting->addWidget(m_difficultyPicker);
m_firstSetting->setAlignment(m_difficultyPicker, Qt::AlignRight);
}
void GenerateNewDialog::setupActions(){
// Connect the signals from the buttonbox to the NewGameDialog.
connect(this->buttonBox, SIGNAL(accepted()), this, SLOT(accept()));
connect(this->buttonBox, SIGNAL(rejected()), this, SLOT(reject()));
}

void GenerateNewDialog::reject(){
qDebug() << "GenerateNewDialog received reject signal.";
QDialog::reject();
close();
}

mcosta
25th February 2011, 23:55
Thank you for your ideas.

1) & 4) The reason I emit a signal on accept() is because I need to get the index of the spinbox that was selected. If there's a better way to do this, let me know!

2) Why would this be a bad thing? I need to free the memory before the dialog ceases to exist, right?



2) When a QObject are destroyed, it delete all children. You have not need to delete them explicitly

For the 1) I suggest you to define a difficulty() public methods that returns m_difficulty and call it after exec from calling code



// For modal Dialog (exec()) you can use a stack variable
GenerateNewDialog dlg(this);

if (QDialog::Accepted == generateNewDialog.exec()) {
difficulty = dlg.difficulty();
}

powerofpi
26th February 2011, 00:03
2) When a QObject are destroyed, it delete all children. You have not need to delete them explicitly


Thanks for that, I wasn't aware of it!



For the 1) I suggest you to define a difficulty() public methods that returns m_difficulty and call it after exec from calling code


I would definitely do that, if exec() didn't cause a segmentation fault :(

As some additional information, I tried to recreate the error with a very small program consisting of only a button with the same dialog window. In this case there was no seg fault and the window was displayed successfully. Could the complication of my program's main window (4 QDockWidgets and a QStatusBar) be causing the seg fault in my main program? Otherwise I used the same code and called it in the same way, so I'm getting more confused...

mcosta
26th February 2011, 00:08
Probably there is something wrong in your code. Check where you explicitly delete Widget and verify if there are logical errors.

powerofpi
26th February 2011, 00:23
Here is the relevant part of my main window code... I'm registering a generateNew slot to receive signals triggered by a new action. Then elsewhere I'm pressing the new button (in a dock widget), causing me to enter my generateNew() slot, and then the seg fault is always occurring on the call to exec(). Could there be a problem with a button press in a dock widget triggering an action and causing a dialog window in the main widget?



#include "mainwindow.h"
#include <QDesktopWidget>
#include <QApplication>
#include <QResizeEvent>
#include "engine/engine.h"
#include "storage/storage.h"
#include "gui/actionmanager.h"

MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent)
{
//Test something manually
//test();

//Create actions
createActions();

//Create window internals
createMainSceneAndView();

//Create dock windows
createDockWindows();

//Additional Settings for this Window
configureWindow();

restoreSettings();

show();
}
void MainWindow::createActions(){

ActionManager::generateNewAction = new QAction(this);
connect(ActionManager::generateNewAction, SIGNAL(triggered()), this, SLOT(generateNew()));

}
void MainWindow::generateNew(){
qDebug() << "MainWindow got generate new event.";

//Create a dialog window to get the requested difficulty
this->generateNewDialog = new GenerateNewDialog(this);
connect(this->generateNewDialog, SIGNAL(difficultySelected(int)), this, SLOT(generationDifficultySelected(int)));

this->generateNewDialog->exec();
}

lauwe
25th March 2011, 21:22
I am having similar problems with a class that inherits from QDialog. In my program i have a QVector<dialog*> with pointers to a number of different instances of the QDialog-derived class. I have a QComboBox that I want to use to activate (show()) these dialogs.

I have two items in the QComboBox and when I activate one dialog everything is fine. But opening the second one leads to a segmentation fault. Note that it does not matter which of the dialogs I open first. But the segmentation fault itself is not caused by me calling show()...



#0 0x00000008 in ?? () at c:/Qt/2010.05/qt/include/QtGui/../../src/gui/kernel/qwidget.h:487
#1 0x00bc0119 in QPainter (this=0x22d468, pd=0x9f504a0) at painting\qpainter.cpp:1489
#2 0x00aed236 in QWidgetPrivate::drawWidget (this=0x9f51600, pdev=0x9fa27c8, rgn=..., offset=..., flags=5, sharedPainter=0x0, backingStore=0x9fa2780) at kernel\qwidget.cpp:5397
#3 0x00c74b31 in QWidgetBackingStore::sync (this=0x9fa2780) at painting\qbackingstore.cpp:1328
#4 0x00ae4f50 in QWidgetPrivate::syncBackingStore (this=0x9f51600) at kernel\qwidget.cpp:1805
#5 0x00af4e75 in QWidget::event (this=0x9f50498, event=0x9f4d360) at kernel\qwidget.cpp:8480
#6 0x00aa9706 in QApplicationPrivate::notify_helper (this=0x3e4c18, receiver=0x9f50498, e=0x9f4d360) at kernel\qapplication.cpp:4396
#7 0x00aa9586 in QApplication::notify (this=0x22fe98, receiver=0x9f50498, e=0x9f4d360) at kernel\qapplication.cpp:4361
#8 0x6a1ff9dc in QCoreApplication::notifyInternal (this=0x22fe98, receiver=0x9f50498, event=0x9f4d360) at kernel\qcoreapplication.cpp:732
#9 0x6a265fbc in QCoreApplication::sendEvent (receiver=0x9f50498, event=0x9f4d360) at kernel//qcoreapplication.h:215
#10 0x6a200a87 in QCoreApplicationPrivate::sendPostedEvents (receiver=0x0, event_type=0, data=0x3e5798) at kernel\qcoreapplication.cpp:1373
#11 0x6a222d2e in qt_internal_proc (hwnd=0x105026c, message=1025, wp=0, lp=0) at kernel\qeventdispatcher_win.cpp:503
#12 0x7e418734 in USER32!GetDC () from C:\WINDOWS\system32\user32.dll
#13 0x0105026c in QGraphicsScenePrivate::drawSubtreeRecursive (this=0x6a222a8a, item=0x105026c, painter=0x401, viewTransform=0x0, exposedRegion=0x0, widget=0x22fcdc, parentOpacity=1.6853403962263272e-307, effectTransform=0x14) at graphicsview\qgraphicsscene.cpp:4717
#14 0x7e418816 in USER32!GetDC () from C:\WINDOWS\system32\user32.dll
#15 0x6a222a8a in qt_fast_timer_proc (timerId=0, user=17105516) at kernel\qeventdispatcher_win.cpp:432
#16 0x7e4189cd in USER32!GetWindowLongW () from C:\WINDOWS\system32\user32.dll
#17 0x00000000 in ?? ()


The QDialog-derived class is generated using Qt Creator and has not been changed by me.