QSettings segfault on Linux
-
Hello,
As the title says, if I create a temporary QSettings after the end of main() function, the application crashed with a segfault on QSettings constructor. A minimal code to get this is:
#include <QtCore/QApplication> #include <QtCore/QSettings> void endMain() { QSettings settings("settings.ini", QSettings::IniFormat); } int main(int argc, char **argv) { atexit(endMain); QCoreApplication(argc, argv); QSettings otherSettings("otherSettings.ini", QSettings::IniFormat); return 0; }
This piece of code makes my application crashes on Linux. However, on Windows, I don't get any problem, and my application ends normally.
Thanks for your help
Fabien MATHIEU
-
I believe
QSettings
queriesQApplication
for things like app name and developer identifier in order to find the location of configuration file (or registry key). Your signature doesn't make sensesettings("settings.ini")
as it seems to imply that you are passing a filename as the first parameter.As such I would make certain that you have a valid
QApplication
at any time you instantiateQSettings
. Since it is customary to do something likeint main(int argc, char** argv) { QApplication app(argc, argv); ... }
your
QApplication
won't exist at the time of youratexit
call.I would personally not use
atexit
with Qt code but you can try invokingQSettings
like this:QSettings settings("Moose Tech", "Facturo-Pro");
-
@msms said:
I believe
QSettings
queriesQApplication
for things like app name and developer identifier in order to find the location of configuration file (or registry key). Your signature doesn't make sensesettings("settings.ini")
as it seems to imply that you are passing a filename as the first parameter.Please forgive my code. Maybe I wrote my post a bit fast. The fact is I don't use the constructor with only the QString parameter, I use the one with the QString and the format. Indeed, with my previous written, the first one in the documentation is used. To be clear, I want to write in a ini file.
As such I would make certain that you have a valid
QApplication
at any time you instantiateQSettings
. Since it is customary to do something likeint main(int argc, char** argv) { QApplication app(argc, argv); ... }
your
QApplication
won't exist at the time of youratexit
call.According to the documentation, QApplication is needed to store the organization name and domain or application name in conjunction with the default QSettings constructor. It is not a requirement in the other case.
I would personally not use
atexit
with Qt code but you can try invokingQSettings
like this:QSettings settings("Moose Tech", "Facturo-Pro");
The use of atexit in my post is only to simplify the undersatnding of my problem. In my application, I use singleton. The destructor of my Singleton occuring after the end of main, I got the crash.
Moreover, I made a mistake about the real error. The crash occurs in the constructor of QSettings after the end of main function, if and only if, an other QSettings has been created during the main (directly or indirectly).
@mcosta said:
Please, attach a stack trace
I don't think stack trace would be useful. Indeed, the crash occurs in QSetting constructor (with a QString and a format), and end up somewhere in the libQt5Core.so without any additional informations about line, function or class.
I change my code in my first post according these remarks.
-
Using valgrind on my minimal code (the one on my first post), it occurs that an invalid read happened. Without surprise, the errors seems to match with the stack trace.
The stack trace is:
0 ?? /home/fabienm/Qt/5.4/gcc_64/lib/libQt5Core.so.5 0x7fca4e7cad6f 1 ?? /home/fabienm/Qt/5.4/gcc_64/lib/libQt5Core.so.5 0x7fca4e7cb0bf 2 QSettings::QSettings(QString const&, QSettings::Format, QObject*) /home/fabienm/Qt/5.4/gcc_64/lib/libQt5Core.so.5 0x7fca4e7cb254 3 endMain main.cpp 6 0x400ac3 4 __run_exit_handlers 82 0x7fca4dcdd259 5 __GI_exit 104 0x7fca4dcdd2a5 6 __libc_start_main 321 0x7fca4dcc2ecc 7 _start 0x4009c9
The output of valgrind is:
Invalid read of size 8 dans endMain() dans /home/fabienm/QSettings_segfault/main.cpp:6 Address 0x0 is not stack'd, malloc'd or (recently) free'd 1: /home/fabienm/Qt/5.4/gcc_64/lib/libQt5Core.so.5.4.1 2: /home/fabienm/Qt/5.4/gcc_64/lib/libQt5Core.so.5.4.1 3: QSettings::QSettings(QString const&, QSettings::Format, QObject*) dans /home/fabienm/Qt/5.4/gcc_64/lib/libQt5Core.so.5.4.1 4: endMain() dans /home/fabienm/QSettings_segfault/main.cpp:6 5: __run_exit_handlers dans /build/buildd/eglibc-2.19/stdlib/exit.c:82 6: exit dans /build/buildd/eglibc-2.19/stdlib/exit.c:104 7: (below main) dans /build/buildd/eglibc-2.19/csu/libc-start.c:321
We see in both case, the code stop somewhere libQt5Core.so, without more information. On my side, I will continue investigation hoping the memory leak is linked to the crash.
-
It's hard to tell what could be the problem. I've had a lot of trouble with static singleton objects in Qt (the dreaded crash at application end), but I've had troubles with them in C++ in general. The destructors or such objects are called in an undefined order. For me things always went wrong when I used them. So, as a result, I advise, if possible to rewrite your program in such a way as not to use a static object, or to force it's destruction to occur before the end of main.
For instance, instead of holding a static object like:
Object obj;
Keep a global pointer to it
Object* obj;
And control its lifetime in
main
:int main() { obj = new Object...; ... delete obj; }
Alternatively, if you wish to track this further, you can try to look at the QSettings source.
Here is a starting point:
I see some QCoreApplication event calls in that file. Those could crash your program for example (but maybe not).
Cheers.
-
So, I recompile Qt for Linux and Windows to be sure, and there is definitively a difference in the behaviour of QSettings. I tracked the crash in qsettings.cpp and I found the responsible line.
In the file, there is the class function QConfFile::fromName(const QString &fileName, bool _userPerms) on line 190. In this function, we try to get a ConfFileHash* on line 194. On Windows, the return value is valid, whereas on Linux, the value is null, that's why my application crash. However, I don't have any ideas to solve it.
I think the difference is on which order are resources destroyed. On Linux, after main ends, a resource has to be destroyed, whereas on Windows it isn't.
I post here the complete stack trace:
Thread 1 (Thread 0x7f5094b3c780 (LWP 7527)): #0 0x00007f50945be5cc in QHash<QString, QConfFile*>::value (this=0x0, akey=...) at ../../include/QtCore/../../src/corelib/tools/qhash.h:618 node = 0x7fff71651dd0 #1 0x00007f50945b49d6 in QConfFile::fromName (fileName=..., _userPerms=true) at io/qsettings.cpp:200 absPath = {static null = {<No data fields>}, d = 0x2209520} confFile = 0x0 locker = {val = 139984066867721} usedHash = 0x0 unusedCache = 0x0 #2 0x00007f50945b8739 in QConfFileSettingsPrivate::QConfFileSettingsPrivate (this=0x2208da0, fileName=..., format=QSettings::IniFormat) at io/qsettings.cpp:1156 No locals. #3 0x00007f50945b50cb in QSettingsPrivate::create (fileName=..., format=QSettings::IniFormat) at io/qsettings.cpp:294 No locals. #4 0x00007f50945bbdfc in QSettings::QSettings (this=0x7fff71651ee0, fileName=..., format=QSettings::IniFormat, parent=0x0) at io/qsettings.cpp:2575 No locals. #5 0x000000000040148d in endMain () at main.cpp:30 settings = {<QObject> = {_vptr.QObject = 0x7fff71651f00, static staticMetaObject = {d = {superdata = 0x0, stringdata = 0x7f50947ed240 <qt_meta_stringdata_QObject>, data = 0x7f50947ed360 <qt_meta_data_QObject>, static_metacall = 0x7f509468f702 <QObject::qt_static_metacall(QObject*, QMetaObject::Call, int, void**)>, relatedMetaObjects = 0x0, extradata = 0x0}}, d_ptr = {d = 0x7f50945d1d1c <(anonymous namespace)::Q_QGS_qtLoggingRegistry::Holder::~Holder()+36>}, static staticQtMetaObject = {d = {superdata = 0x0, stringdata = 0x7f509483a740 <qt_meta_stringdata_Qt>, data = 0x7f5094844ac0 <qt_meta_data_Qt>, static_metacall = 0x0, relatedMetaObjects = 0x0, extradata = 0x0}}}, static staticMetaObject = {d = {superdata = 0x7f509493fb40 <QObject::staticMetaObject>, stringdata = 0x7f509484f900 <qt_meta_stringdata_QSettings>, data = 0x7f509484f940 <qt_meta_data_QSettings>, static_metacall = 0x7f5094718e20 <QSettings::qt_static_metacall(QObject*, QMetaObject::Call, int, void**)>, relatedMetaObjects = 0x0, extradata = 0x0}}} #6 0x00007f5093a7d259 in __run_exit_handlers (status=0, listp=0x7f5093dff6c8 <__exit_funcs>, run_list_atexit=run_list_atexit@entry=true) at exit.c:82 atfct = <optimized out> onfct = <optimized out> cxafct = <optimized out> f = <optimized out> #7 0x00007f5093a7d2a5 in __GI_exit (status=<optimized out>) at exit.c:104 No locals. #8 0x00007f5093a62ecc in __libc_start_main (main=0x40153c <main(int, char**)>, argc=1, argv=0x7fff71652028, init=<optimized out>, fini=<optimized out>, rtld_fini=<optimized out>, stack_end=0x7fff71652018) at libc-start.c:321 result = <optimized out> unwind_buf = {cancel_jmp_buf = {{jmp_buf = {0, -6701343962190558468, 4199168, 140735095840800, 0, 0, 6701050451662228220, 6746722540675549948}, mask_was_saved = 0}}, priv = {pad = {0x0, 0x0, 0x403b20 <__libc_csu_init>, 0x7fff71652028}, data = {prev = 0x0, cleanup = 0x0, canceltype = 4209440}}} not_first_call = <optimized out> #9 0x0000000000401329 in _start () No symbol table info available.
@msms said:
I see some QCoreApplication event calls in that file. Those could crash your program for example (but maybe not).
Indeed, there are some QCoreApplication event calls. I haven't got into this calls, but these calls are static, so maybe the QCoreApplication isn't needed. The above stack trace seems exclude this theory.
In all case, thanks for your help
Cheers