PDA

View Full Version : QSqlQuery segfault



pdoria
13th March 2012, 01:24
Hi all,

In a bit of pickle here with app segfaulting whenever I use either prepare() or exec() methods of QSqlQuery .. :S

My app creates a unique database connection for each thread it spawns (working for everything else...)

The problematic code:


QSqlQuery query ( this->connAvl->db );
db is a pointer to the database object from another class so it should be passing the correct connection... As a matter of fact on another method of the class I use the exact same code with no problems! :S

whenever I use:

query.prepare("INSERT INTO garmin_packets (zulu_timestamp, unit_imei, packet_id, fmi_packet_id, unique_id, driver_idx, driver_status) "
"VALUES (?, ?, ?, ?, ?, ?, ?)");

Application segfaults with

==26283== Invalid read of size 8
==26283== at 0x4C288A0: QSqlResult::isForwardOnly() const (qsqlresult.cpp:551)
==26283== by 0x4C1A94F: QSqlQuery::isForwardOnly() const (qsqlquery.cpp:803)
==26283== by 0x4C1BC02: QSqlQuery::prepare(QString const&) (qsqlquery.cpp:895)
==26283== by 0x41D105: GarminFmi::d607_driver_status_update(QDataStream&) (garminfmi.cpp:613)
==26283== by 0x41F89D: GarminFmi::parseFmiPacket() (garminfmi.cpp:162)
==26283== by 0x418B6B: TeltonikaUnit::parseDataField(unsigned char, QDataStream&) (teltonikaunit.cpp:467)
==26283== by 0x418FA2: TeltonikaUnit::parseData(QByteArray&) (teltonikaunit.cpp:408)
==26283== by 0x419AE7: TeltonikaUnit::incomingData() (teltonikaunit.cpp:277)
==26283== by 0x420B58: TeltonikaUnit::qt_metacall(QMetaObject::Call, int, void**) (moc_teltonikaunit.cpp:86)
==26283== by 0x53089C9: QMetaObject::activate(QObject*, QMetaObject const*, int, void**) (qobject.cpp:3285)
==26283== by 0x4EF7D37: QAbstractSocketPrivate::canReadNotification() (qabstractsocket.cpp:626)
==26283== by 0x4EE6540: QReadNotifier::event(QEvent*) (qnativesocketengine.cpp:1094)
==26283== Address 0x8 is not stack'd, malloc'd or (recently) free'd
==26283==
==26283== Process terminating with default action of signal 11 (SIGSEGV)
==26283== Access not within mapped region at address 0x8
==26283== at 0x4C288A0: QSqlResult::isForwardOnly() const (qsqlresult.cpp:551)
==26283== by 0x4C1A94F: QSqlQuery::isForwardOnly() const (qsqlquery.cpp:803)
==26283== by 0x4C1BC02: QSqlQuery::prepare(QString const&) (qsqlquery.cpp:895)
==26283== by 0x41D105: GarminFmi::d607_driver_status_update(QDataStream&) (garminfmi.cpp:613)
==26283== by 0x41F89D: GarminFmi::parseFmiPacket() (garminfmi.cpp:162)
==26283== by 0x418B6B: TeltonikaUnit::parseDataField(unsigned char, QDataStream&) (teltonikaunit.cpp:467)
==26283== by 0x418FA2: TeltonikaUnit::parseData(QByteArray&) (teltonikaunit.cpp:408)
==26283== by 0x419AE7: TeltonikaUnit::incomingData() (teltonikaunit.cpp:277)
==26283== by 0x420B58: TeltonikaUnit::qt_metacall(QMetaObject::Call, int, void**) (moc_teltonikaunit.cpp:86)
==26283== by 0x53089C9: QMetaObject::activate(QObject*, QMetaObject const*, int, void**) (qobject.cpp:3285)
==26283== by 0x4EF7D37: QAbstractSocketPrivate::canReadNotification() (qabstractsocket.cpp:626)
==26283== by 0x4EE6540: QReadNotifier::event(QEvent*) (qnativesocketengine.cpp:1094)

Sorry for the long dump... :)

Now I've tested if the database was open ... no problems there...

Am I missing something altogether obvious?!

Any help appreciated ;)

Spitfire
13th March 2012, 17:47
Try replacing offending line with
QSqlQuery query( QSqlDatabase::database( "your_connection_name" ) ); or even
QSqlQuery query( QSqlDatabase::database( this->connAvl->db.connectionName() ) ); and see what happens.

I've seen problems when using cached database objects with QSqlQuery() (no idea why though) but QSqlDatabase::database() always saved the day for me.

pdoria
14th March 2012, 19:32
That was a good tip, but still no joy :(

App still crashes at query.prepare() (which in turn calls isForwardOnly --> this is where the segfault pops up)

ChrisW67
15th March 2012, 00:27
Clean your project and completely rebuild. Does the problem persist?

pdoria
15th March 2012, 16:50
yes unfortunately :(

yes unfortunately :(

Now posting modifications to code (still segfaulting btw... ) and trace

Modified the code so that the class had its own database connection (was using calling class connection, via passed pointer to it)
This is running in its own thread, btw...

declarations, extract:


class GarminFmi
{
protected:
TeltonikaUnit * connAvl; // this holds the connected AVL unit
QSqlDatabase db;
QString dbConnectionName;
char dbUnique[76]; // a placeholder for generating a db connection unique name
}

Class constructor, extract:


GarminFmi::GarminFmi( QByteArray & fmiPacket, TeltonikaUnit * avl )
{
this->debug = true;

sprintf ( dbUnique, "DB%08x%08x", rand(), rand() );
dbConnectionName=dbUnique;
db = QSqlDatabase::addDatabase ( "QPSQL", dbUnique );
db.setHostName ( "localhost" );
db.setDatabaseName ( "lalala" );
db.setUserName ( "lalala" );
db.setPassword ( "lalala" );
if ( !db.open() ) {
printf ( "***********************************************\r\ n" );
printf ( "* CRITICAL ERROR! Cannot connect to database! *\r\n" );
printf ( "***********************************************\r\ n" );
return;
}
}


Code that segfaults (namely on query.prepare() )

driver_status_d607_receipt_data_type GarminFmi::d607_driver_status_update(QDataStream& stream)
{
QDateTime dateTime;
QDateTime dateTimeStart;
QString humanDate;
QSqlQuery query( QSqlDatabase::database( this->db.connectionName() ) );

driver_status_d607_data_type driver_status;

qDebug() << this->db.connectionName();

stream >> driver_status.change_id
>> driver_status.change_time
>> driver_status.driver_status
>> driver_status.driver_idx
>> driver_status.reserved[0]
>> driver_status.reserved[1]
>> driver_status.reserved[3];

//! \note Date/Time starts at 1989-12-31 00:00:00
dateTimeStart = QDateTime::fromString ( "M12d31y8900:00:00", "'M'M'd'd'y'yyhh:mm:ss" );
quint32 start = dateTimeStart.toTime_t();
dateTime=QDateTime::fromTime_t ( driver_status.change_time + start );
humanDate = dateTime.toString ( "yyyy-MM-dd hh:mm:ss" );

// a little check.... ;)
printf("Time: %s\r\n", humanDate.toLatin1().data());
printf("Imei: %s\r\n", this->connAvl->data.imei.data());
printf("Packet: %04x\r\n", ID_FMI_PACKET );
printf("FMI Packet: %04x\r\n", FMI_A607_DRIVER_STATUS_UPDATE);
printf("Change id: %d\r\n", driver_status.change_id);
printf("Driver idx: %d\r\n", driver_status.driver_idx);
printf("Driver status: %d\r\n", driver_status.driver_status);

// update garmin_packets table.
QString sql = "INSERT INTO garmin_packets (zulu_timestamp, unit_imei, packet_id, fmi_packet_id, unique_id, driver_idx, driver_status) VALUES (?, ?, ?, ?, ?, ?, ?)";
query.prepare( sql );
query.bindValue(0, humanDate.toLatin1().data());
query.bindValue(1, this->connAvl->data.imei.data());
query.bindValue(2, ID_FMI_PACKET);
query.bindValue(3, FMI_A607_DRIVER_STATUS_UPDATE);
query.bindValue(4, driver_status.change_id);
query.bindValue(5, driver_status.driver_idx);
query.bindValue(6, driver_status.driver_status);
query.exec ();
printf("GOT PAST THIS!\r\n");

// cleanup
query.clear();

// prepare the receipt data for this packet
driver_status_d607_receipt_data_type receipt_data;
receipt_data.status_change_id = driver_status.change_id;
receipt_data.result_code = true;
receipt_data.driver_idx = driver_status.driver_idx;
receipt_data.reserved[0] = 0x0;
receipt_data.reserved[1] = 0x0;

return receipt_data;
}


Trace:

==20045== Invalid read of size 4
==20045== at 0x4147ACE9: QSqlQuery::prepare(QString const&) (in /usr/lib/libQtSql.so.4.7.4)
==20045== by 0x806466F: GarminFmi::parseFmiPacket() (garminfmi.cpp:186)
==20045== by 0x8052D70: TeltonikaUnit::parseDataField(unsigned char, QDataStream&) (teltonikaunit.cpp:467)
==20045== by 0x80529AF: TeltonikaUnit::parseData(QByteArray&) (teltonikaunit.cpp:408)
==20045== by 0x8051FF0: TeltonikaUnit::incomingData() (teltonikaunit.cpp:277)
==20045== by 0x8067B35: TeltonikaUnit::qt_metacall(QMetaObject::Call, int, void**) (moc_teltonikaunit.cxx:86)
==20045== by 0x4EDD928D: QMetaObject::metacall(QObject*, QMetaObject::Call, int, void**) (in /usr/lib/libQtCore.so.4.7.4)


I'm getting a unique connection to the DB, no problems there...
It seems as if the query object isn't getting properly initialized? :confused:
Results exactly the same on 32 and 64 bit platforms... (note the QT version on the libraries)

What on earth could be causing query.prepare(), query.exec() to segfault?! :confused:

Sorry for the very long post

Thx in advance for any insight

ChrisW67
16th March 2012, 01:00
I am confused.

The trace indicates that the failure is occurring in GarminFmi::parseFmiPacket() (garminfmi.cpp:186) ultimately reached after a slot call to TeltonikaUnit::incomingData().
You are posting a different function GarminFmi::d607_driver_status_update() telling us it fails there. The trace makes no mention of the function you have posted.

pdoria
16th March 2012, 01:48
Thank you Chris for taking the time to look into this :)

the trace isn't all there due to space limitation ... going to post the caller fx and the complete trace in the next msg

Added after 8 minutes:

Calling extract:

case FMI_A607_DRIVER_STATUS_UPDATE: {
printf("Garmin sent FMI_A607_DRIVER_STATUS_UPDATE\r\n");
driver_status_d607_receipt_data_type receipt_data;
receipt_data = d607_driver_status_update ( stream ); // LINE 186
msg_receipt = d607_driver_status_update_receipt( receipt_data );
receipt = createSerialPacket(ID_FMI_PACKET, msg_receipt);
break;
}

full trace:

==3540== Conditional jump or move depends on uninitialised value(s)
==3540== at 0x4147ACEE: QSqlQuery::prepare(QString const&) (in /usr/lib/libQtSql.so.4.7.4)
==3540== by 0x806466F: GarminFmi::parseFmiPacket() (garminfmi.cpp:186)
==3540== by 0x8052D70: TeltonikaUnit::parseDataField(unsigned char, QDataStream&) (teltonikaunit.cpp:467)
==3540== by 0x80529AF: TeltonikaUnit::parseData(QByteArray&) (teltonikaunit.cpp:408)
==3540== by 0x8051FF0: TeltonikaUnit::incomingData() (teltonikaunit.cpp:277)
==3540== by 0x8067AED: TeltonikaUnit::qt_metacall(QMetaObject::Call, int, void**) (moc_teltonikaunit.cxx:86)
==3540== by 0x4EDD928D: QMetaObject::metacall(QObject*, QMetaObject::Call, int, void**) (in /usr/lib/libQtCore.so.4.7.4)
==3540== by 0x4063B1F: ???
==3540== Uninitialised value was created by a heap allocation
==3540== at 0x4006865: operator new(unsigned int) (vg_replace_malloc.c:255)
==3540== by 0x4020AF6: ??? (in /usr/lib/qt4/plugins/sqldrivers/libqsqlpsql.so)
==3540== by 0x402205F: ??? (in /usr/lib/qt4/plugins/sqldrivers/libqsqlpsql.so)
==3540== by 0x806466F: GarminFmi::parseFmiPacket() (garminfmi.cpp:186)
==3540== by 0x8052D70: TeltonikaUnit::parseDataField(unsigned char, QDataStream&) (teltonikaunit.cpp:467)
==3540== by 0x80529AF: TeltonikaUnit::parseData(QByteArray&) (teltonikaunit.cpp:408)
==3540== by 0x8051FF0: TeltonikaUnit::incomingData() (teltonikaunit.cpp:277)
==3540== by 0x8067AED: TeltonikaUnit::qt_metacall(QMetaObject::Call, int, void**) (moc_teltonikaunit.cxx:86)
==3540== by 0x4EDD928D: QMetaObject::metacall(QObject*, QMetaObject::Call, int, void**) (in /usr/lib/libQtCore.so.4.7.4)
==3540== by 0x4063B1F: ???
==3540==
==3540== Invalid read of size 4
==3540== at 0x4147ADB8: QSqlQuery::prepare(QString const&) (in /usr/lib/libQtSql.so.4.7.4)
==3540== by 0x806466F: GarminFmi::parseFmiPacket() (garminfmi.cpp:186)
==3540== by 0x8052D70: TeltonikaUnit::parseDataField(unsigned char, QDataStream&) (teltonikaunit.cpp:467)
==3540== by 0x80529AF: TeltonikaUnit::parseData(QByteArray&) (teltonikaunit.cpp:408)
==3540== by 0x8051FF0: TeltonikaUnit::incomingData() (teltonikaunit.cpp:277)
==3540== by 0x8067AED: TeltonikaUnit::qt_metacall(QMetaObject::Call, int, void**) (moc_teltonikaunit.cxx:86)
==3540== by 0x4EDD928D: QMetaObject::metacall(QObject*, QMetaObject::Call, int, void**) (in /usr/lib/libQtCore.so.4.7.4)
==3540== by 0x4063B1F: ???
==3540== Address 0x6b is not stack'd, malloc'd or (recently) free'd
==3540==
==3540==
==3540== Process terminating with default action of signal 11 (SIGSEGV)
==3540== Access not within mapped region at address 0x6B
==3540== at 0x4147ADB8: QSqlQuery::prepare(QString const&) (in /usr/lib/libQtSql.so.4.7.4)
==3540== by 0x806466F: GarminFmi::parseFmiPacket() (garminfmi.cpp:186)
==3540== by 0x8052D70: TeltonikaUnit::parseDataField(unsigned char, QDataStream&) (teltonikaunit.cpp:467)
==3540== by 0x80529AF: TeltonikaUnit::parseData(QByteArray&) (teltonikaunit.cpp:408)
==3540== by 0x8051FF0: TeltonikaUnit::incomingData() (teltonikaunit.cpp:277)
==3540== by 0x8067AED: TeltonikaUnit::qt_metacall(QMetaObject::Call, int, void**) (moc_teltonikaunit.cxx:86)
==3540== by 0x4EDD928D: QMetaObject::metacall(QObject*, QMetaObject::Call, int, void**) (in /usr/lib/libQtCore.so.4.7.4)
==3540== by 0x4063B1F: ???

that query.prepare() mentioned at the 1st line of the trace lives in driver_status_d607_receipt_data_type GarminFmi::d607_driver_status_update(QDataStream& stream) as shown in previous msgs

I sure I'm overlooking something altogether too obvious... :o

Thx for the help mate

wysota
16th March 2012, 01:58
Address 0x6b is not stack'd
You have a null pointer somewhere (this? or this->connAvl?).


And please give us a backtrace from the debugger and not from valgrind.

pdoria
16th March 2012, 03:19
Hi wysota! long time no see! :)

Now I know you're gonna crucify me for this ;) .... but ... how do I get a backtrace from the debugger? :o
BR m8!

EDIT: pls disregard... already downloading the 546MB debuginfo packages... (qt-debuginfo==356MB?? omg!)

Should post the backtrace momentarily... ;)

Added after 18 minutes:

that's all what I got:


Program received signal SIGSEGV, Segmentation fault.
[Switching to Thread 0xb7c9ab70 (LWP 3951)]
0x41487754 in QSqlResult::isForwardOnly (this=0x0) at kernel/qsqlresult.cpp:553
553 return d->forwardOnly;

Added after 36 minutes:

a more meaningful trace:


Thread 2 (Thread 0xb7c9ab70 (LWP 4399)):
#0 0x41487754 in QSqlResult::isForwardOnly (this=0x746565) at kernel/qsqlresult.cpp:553
No locals.
#1 0x4147a281 in QSqlQuery::isForwardOnly (this=0xb7c999ec) at kernel/qsqlquery.cpp:804
No locals.
#2 0x4147ad00 in QSqlQuery::prepare (this=0xb7c999ec, query=...) at kernel/qsqlquery.cpp:899
fo = <optimized out>
#3 0x080669ba in GarminFmi::d607_driver_status_update (this=0xb7c99b84, stream=...) at /home/pdoria/projects/teltonika_tcp_server3_garmin_support/garminfmi.cpp:648
dateTimeStart = {d = {d = 0xb7329840}}
humanDate = {static null = {<No data fields>}, static shared_null = {ref = {_q_value = 1}, alloc = 0, size = 0, data = 0x8075552, clean = 0, simpletext = 0, righttoleft = 0, asciiCache = 0, capacity = 0, reserved = 0, array = {
0}}, static shared_empty = {ref = {_q_value = 1}, alloc = 0, size = 0, data = 0x4ef088de, clean = 0, simpletext = 0, righttoleft = 0, asciiCache = 0, capacity = 0, reserved = 0, array = {0}}, d = 0xb732d5f0,
static codecForCStrings = 0x0}
driver_status = {change_id = 9, change_time = 700752930, driver_status = 2, driver_idx = 0 '\000', reserved = "\000\000"}
dateTime = {d = {d = 0xb7329ec0}}
query = {d = 0xb731bf00}
start = 631065600
sql = {static null = {<No data fields>}, static shared_null = {ref = {_q_value = 1}, alloc = 0, size = 0, data = 0x8075552, clean = 0, simpletext = 0, righttoleft = 0, asciiCache = 0, capacity = 0, reserved = 0, array = {0}},
static shared_empty = {ref = {_q_value = 1}, alloc = 0, size = 0, data = 0x4ef088de, clean = 0, simpletext = 0, righttoleft = 0, asciiCache = 0, capacity = 0, reserved = 0, array = {0}}, d = 0xb7325b90,
static codecForCStrings = 0x0}

sql == null????
after
QString sql = "INSERT INTO garmin_packets (zulu_timestamp, unit_imei, packet_id, fmi_packet_id, unique_id, driver_idx, driver_status) VALUES (?, ?, ?, ?, ?, ?, ?)"; ??

Spitfire
16th March 2012, 10:22
null (notice lower case) is actually a variable in the string put there for some compatibility reasons. It's just an empty structure - that's why it has no data fields.
If you look at humanDate - it has the same static null variable with no fields. Any other string will have this.
Name is confusing but that's not a reason for your problem.

Edit:
Btw do you implement your own QSqlDriver?

wysota
16th March 2012, 10:55
Please post a full backtrace, not only the first frame.

From what you can see here:

0x41487754 in QSqlResult::isForwardOnly (this=0x0) at kernel/qsqlresult.cpp:553
"this" is null so the QSqlResult object is invalid. If you look at the full backtrace and find where the trace leaves your code and enters Qt's, you'll pinpoint the problem in your code that is causing the faulty behaviour.

pdoria
16th March 2012, 17:02
Ok. the full backtrace is attached. Thx for taking the time to look at it :)

wysota
16th March 2012, 17:50
Show us code around garminfmi.cpp:648

Your "this" pointer has changed its value which suggests the problem is with an uninitialized and not a null pointer.

pdoria
16th March 2012, 18:02
As usual one's blindness comes into play...
found the bug.


driver_status.reserved[3];
overstepped struct's boundaries here... :S
the typedef:

typedef struct /* D607 */
{
quint32 change_id; /* unique identifier */
quint32 change_time; /* timestamp of status change */
quint32 driver_status; /* ID corresponding to the new driver status */
quint8 driver_idx;
quint8 reserved[3]; /* set to 0 */
} driver_status_d607_data_type;

Thx to all that took the time to look at this with special thanks to ChrisW67, wysota, Spitfire and sry about the noise... :o

ChrisW67
16th March 2012, 22:01
Nice to see you found the culprit. I was only getting more confused because your full gdb.txt does not contain the "this=0x0" that Wysota picked up on. You gotta love it.