PDA

View Full Version : Segmentation fault



MarkoSan
14th October 2007, 14:28
Hello again!

I have following code:



CBrowserWindow::CBrowserWindow(QWidget *parent, MySQLConnect* pDataBase, QString sTableName)
: QWidget(parent)
{
Q_CHECK_PTR(pDataBase); // if database connection is NULL, we have a big problem

m_pModel=new QSqlRelationalTableModel(this); // creates new model
Q_CHECK_PTR(m_pModel); // checks for succesful creation
m_pModel->setTable(sTableName); // sets table name

m_pColumnNames=new QStringList(); // creates new string list
Q_CHECK_PTR(m_pColumnNames); // checks for succesful creation

// fetches record
m_pTableRecord=new QSqlRecord(); // creates new record
Q_CHECK_PTR(m_pTableRecord); // checks for susccesful creation
//m_pTableRecord=&pDataBase->m_pDatabase->record(sTableName); // fetches column names
m_pTableRecord=&pDataBase->m_pDatabase->record(sTableName); // fetches column names


if (!m_pTableRecord->isEmpty()) {
for (m_iIndex=0; m_iIndex<m_pTableRecord->count(); m_iIndex++) {
m_pColumnNames->append(m_pTableRecord->fieldName(m_iIndex));
}
} // if

createBrowserContens(pDataBase, m_pColumnNames); // creates browser controls

delete m_pModel; // deletes pModel;
delete m_pTableRecord; // deletes m_pTableRecord
// just to be sure
m_pModel=0;
m_pTableRecord=0;
}and in the line


m_pTableRecord=&pDataBase->m_pDatabase->record(sTableName); // fetches column namesI get segmentation fault. What I am trying to do is to dynamically fetch table column names from mysql database and then create table widget for record display. Why do I get segfault?

Here is class description:

class CBrowserWindow : public QWidget
{
Q_OBJECT
public:
CBrowserWindow(QWidget *parent = 0, MySQLConnect* pDataBase=0, QString sTableName="");

~CBrowserWindow();

private:
QStringList* m_pColumnNames; // column names for selected database

private:
// buttons
QPushButton* m_pButtonAdd; // button for addition of record
QPushButton* m_pButtonChange; // button for change of record
QPushButton* m_pButtonDelete; // button for deletion of record
QPushButton* m_pButtonSelect; // button for selection of record

private:
// layouts
QHBoxLayout* m_pHorizLayout; // horizontal leyout
QVBoxLayout* m_pVertLayout; // vertical layout

private:
// mebmers needed for column idetification
QSqlRelationalTableModel* m_pModel; // pointer to pmodel
QSqlRecord* m_pTableRecord; // pointer to database record
QTableView* m_pView; // pointer to view
QGridLayout* m_pGridLayout; // pointer to grid layout
quint16 m_iIndex; // index in for loops - this type is guaranteed to be 16-bit on all platforms supported by Qt

private:
// private methods
void createBrowserContens(MySQLConnect* pDatabase, QStringList* pColumnNames); // creates table on widget
};

#endif

marcel
14th October 2007, 14:38
I think because you're taking the address of a temporary QSqlRecord -- the one returned by record(...).
Don't use a pointer to a QSqlRecord or do it like this:


QSqlRecord rec=pDataBase->m_pDatabase->record(sTableName); // fetches column names
m_pTableRecord = new QSqlRecord( rec );

MarkoSan
14th October 2007, 15:23
I've changed the code in the way you instructed, i get same segmentation fault.

marcel
14th October 2007, 15:39
Then you must have a NULL pointer somewhere. What about m_pDatabase? Are you sure it is always valid?

MarkoSan
14th October 2007, 16:25
Well, I've checked with gdb, none of actors pointer have NULL or 0 value, according to gdb. What the heck is going on??

jacek
14th October 2007, 16:57
Could you post the backtrace?

MarkoSan
14th October 2007, 19:16
Could you post the backtrace?

I am using gdb through KDevelop, how do I get backtrace?

jacek
14th October 2007, 21:36
I am using gdb through KDevelop, how do I get backtrace?
I've never tried it, but there's a "GDB" tab where you can issue commands. In standalone GDB you do it this way:

$ gdb ./app
(gdb) run
<program crashes>
(gdb) bt
<backtrace>

anonyme_84
14th October 2007, 22:57
Hi,


I am using gdb through KDevelop, how do I get backtrace?

With Kdevelop, you have got a tab called "backtrace" when you run your application in debug mode.

Bye.

MarkoSan
15th October 2007, 10:16
Well, my friends, here is a backtrace:


(gdb) run
Starting program: /home/markofr/working_copy/qKobilica/bin/qkobilica
[Thread debugging using libthread_db enabled]
[New Thread 47848586376464 (LWP 9931)]
Qt: gdb: -nograb added to command-line options.
Use the -dograb option to enforce grabbing.

Program received signal SIGSEGV, Segmentation fault.
[Switching to Thread 47848586376464 (LWP 9931)]
0x0000000000000000 in ?? ()
(gdb) bt
#0 0x0000000000000000 in ?? ()
#1 0x00002b8496d9e4e3 in QSqlDatabase::record () from /usr/lib/libQtSql.so.4
#2 0x00000000004072c8 in CBrowserWindow (this=0x6cff50, parent=0x663e70, pDataBase=0x66f220, sTableName=@0x7fff13f42830) at cbrowserwindow.cpp:17
#3 0x0000000000405b48 in qKobilica::browseSifrantKrajev (this=0x663e70) at qkobilica.cpp:91
#4 0x0000000000408a5d in qKobilica::qt_metacall (this=0x663e70, _c=QMetaObject::InvokeMetaMethod, _id=0, _a=0x7fff13f42e00) at moc_qkobilica.cpp:66
#5 0x00002b8497c2f770 in QMetaObject::activate () from /usr/lib/libQtCore.so.4
#6 0x00002b8497c2f969 in QMetaObject::activate () from /usr/lib/libQtCore.so.4
#7 0x00002b849718d9ab in QAction::triggered () from /usr/lib/libQtGui.so.4
#8 0x00002b849718f4b8 in QAction::activate () from /usr/lib/libQtGui.so.4
#9 0x00002b849754fea9 in ?? () from /usr/lib/libQtGui.so.4
#10 0x00002b849755264a in QMenu::mouseReleaseEvent () from /usr/lib/libQtGui.so.4
#11 0x00002b84971e15d9 in QWidget::event () from /usr/lib/libQtGui.so.4
#12 0x00002b849754de85 in QMenu::event () from /usr/lib/libQtGui.so.4
#13 0x00002b8497194d51 in QApplicationPrivate::notify_helper () from /usr/lib/libQtGui.so.4
#14 0x00002b8497195949 in QApplication::notify () from /usr/lib/libQtGui.so.4
#15 0x00002b8497c1e846 in QCoreApplication::notifyInternal () from /usr/lib/libQtCore.so.4
#16 0x00002b849719fe73 in ?? () from /usr/lib/libQtGui.so.4
#17 0x00002b84971fa37c in ?? () from /usr/lib/libQtGui.so.4
#18 0x00002b84971f8239 in QApplication::x11ProcessEvent () from /usr/lib/libQtGui.so.4
#19 0x00002b8497226599 in ?? () from /usr/lib/libQtGui.so.4
#20 0x00002b8499f8ffd3 in g_main_context_dispatch () from /usr/lib/libglib-2.0.so.0
#21 0x00002b8499f932dd in ?? () from /usr/lib/libglib-2.0.so.0
#22 0x00002b8499f9380e in g_main_context_iteration () from /usr/lib/libglib-2.0.so.0
#23 0x00002b8497c45f4e in QEventDispatcherGlib::processEvents () from /usr/lib/libQtCore.so.4
#24 0x00002b8497225e07 in ?? () from /usr/lib/libQtGui.so.4
#25 0x00002b8497c1bb31 in QEventLoop::processEvents () from /usr/lib/libQtCore.so.4
#26 0x00002b8497c1bc86 in QEventLoop::exec () from /usr/lib/libQtCore.so.4
#27 0x00002b8497c1effc in QCoreApplication::exec () from /usr/lib/libQtCore.so.4
#28 0x00002b8497194928 in QApplication::exec () from /usr/lib/libQtGui.so.4
#29 0x00000000004062fd in main (argc=1, argv=0x7fff13f44638) at main.cpp:13

marcel
15th October 2007, 10:23
Are you sure you instantiate the QSqlDatabase? It doesn't look like you do.
Can you post the code where you create it? It might be the fact that QSqlDatabase::addDatabase gives you a local copy and you take its address. The pointer will become invalid by the time you pass it to the constructor.
Why don't you use const refs instead?

MarkoSan
15th October 2007, 10:29
Well, this is a code:


// sets up database - params QString db_user,QString db_pass,QString db_name,QString host,QString type
m_pDatabaseConnection=new MySQLConnect(QString("username"), QString("password"), QString("premade_database"));
Q_CHECK_PTR(m_pDatabaseConnection);


I am quite sure I will be forced to rewrite the MySQLConection class since it obviously does not work!!!

marcel
15th October 2007, 10:39
Yes, but I was referring to the internal QSqlDatabase pointer. The one from MySqlConnect.

MarkoSan
15th October 2007, 10:42
Ok, just a second. Did you mean this chunk of code:

MySQLConnect::MySQLConnect(QString db_user, QString db_pass, QString db_name, QString host, QString type) {

//connect to database
QSqlDatabase db = QSqlDatabase::addDatabase(type);
db.setHostName(host);
db.setDatabaseName(db_name);
db.setUserName(db_user);
db.setPassword(db_pass);

//get a pointer to a database connection
m_pDatabase = &QSqlDatabase::database();
Q_CHECK_PTR(m_pDatabase);

//sql table model == read/write model --> navigate and modify individual sql tables
m_pModel = new QSqlRelationalTableModel(this);
Q_CHECK_PTR(m_pModel);

//model->setTable(db_table);
//all changes will be cached in the model until either submitAll() or revertAll() is called
m_pModel->setEditStrategy(QSqlTableModel::OnManualSubmit);

//populates the model with data from the table, using the specified filter and sort conditions
//model->select();
}

//QSqlDatabase* MySQLConnect::m_pDatabase=0;

/*
//this function is called if a refresh button is clicked
void MySQLConnect::refresh_everything() {
model->select();
}

void MySQLConnect::change_mysql() {
//submits all pending changes to the mysql database
model->submitAll();
}
*/

marcel
15th October 2007, 10:50
Rewrite it like this:


MySQLConnect::MySQLConnect(QString db_user, QString db_pass, QString db_name, QString host, QString type) {
//connect to database
m_Database = QSqlDatabase::addDatabase(type);
m_Database.setHostName(host);
m_Database.setDatabaseName(db_name);
m_Database.setUserName(db_user);
m_Database.setPassword(db_pass);
bool openedOK = m_Database.open();

m_pModel = new QSqlRelationalTableModel(this);
Q_CHECK_PTR(m_pModel);
m_pModel->setEditStrategy(QSqlTableModel::OnManualSubmit);
...
}


replace m_pDatabase with m_Database (not a pointer).

MarkoSan
16th October 2007, 12:55
Hi. is there possible fault in the message:

mysqlconnect.cpp: In constructor ‘MySQLConnect::MySQLConnect(QString, QString, QString, QString, QString)’:
mysqlconnect.cpp:17: warning: taking address of temporaryaccording to following code chunk:

m_pDatabase = &QSqlDatabase::database();?

marcel
16th October 2007, 12:58
:) Come on... This is exactly what I was trying to tell you in my last posts.

MarkoSan
16th October 2007, 13:00
Ok, Marcel sorry for stutpidity, but how do I change previous statements to make them work, can you give me an example please?

marcel
16th October 2007, 13:09
No problem. Take a look at post #15.
You have to change m_pDatabase in class declaration. You don't need a pointer to a QSqlDatabase. You can declare it as
QSqlDatabase m_Database; .

Then make the appropriate changes in the constructor, as I've shown you.
Also, you will have to change every line of code where m_pDatabse was used, since now it is not a pointer anymore.

MarkoSan
16th October 2007, 13:11
Ok, let me get to work now, I'll report results ...

jpn
20th October 2007, 14:11
I think most of the QtSql examples I've seen simply access database connection via the static method QSqlDatabase::database() whenever needed, without the need of storing connection as member variable anywhere. QSqlDatabase::database() seems to be basically a call to QHash::value() in a thread-safe manner so it's not that inefficient at least. :)

MarkoSan
20th October 2007, 15:56
Ok, I know, I've complicated things a bit here but I simply wanted to have A SINGLE INSTANCE of object that connects to database, i.e., an instance of application is allowed to connect to database ONLY ONCE. Is this right policy or not?

Frozenjim
13th October 2008, 16:52
This thread has really helped me out, but I am still somewhat confused about what appears to be the foundation of the problem (I am fairly new to C++):
How do you know if you should be creating a pointer or not? How do I know when to use *model or model?

The documentation from Trolltech (http://doc.trolltech.com/4.3/qsqlquerymodel.html) actually makes it even worse for a beginner because they seem to use the two interchangeably - but when I do so, I get Segmentation faults if I can compile at all:

QSqlQueryModel *model = new QSqlQueryModel;
model->setQuery("SELECT name, salary FROM employee");
model->setHeaderData(0, Qt::Horizontal, tr("Name"));
model->setHeaderData(1, Qt::Horizontal, tr("Salary"));

QTableView *view = new QTableView;
view->setModel(model);
view->show();

We set the model's query, then we set up the labels displayed in the view header.

QSqlQueryModel can also be used to access a database programmatically, without binding it to a view:

QSqlQueryModel model;
model.setQuery("SELECT * FROM employee");
int salary = model.record(4).value("salary").toInt();

jacek
19th October 2008, 23:40
How do you know if you should be creating a pointer or not?
It depends on how long you need the object. If you create it on the stack it will be destroyed when it goes out of scope, so all objects that need to exist longer should be created using new operator. If you use a model only within one function, you can create it on the stack. If you pass a model to a view, it has to exist as long as the view, so you have to use new.


The documentation from Trolltech actually makes it even worse for a beginner because they seem to use the two interchangeably
The docs assume you know C++.