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



  • This post is deleted!


  • Please, attach a stack trace



  • I believe QSettings queries QApplication 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 sense settings("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 instantiate QSettings. Since it is customary to do something like

    int main(int argc, char** argv) {
        QApplication app(argc, argv);
        ...
    }
    

    your QApplication won't exist at the time of your atexit call.

    I would personally not use atexit with Qt code but you can try invoking QSettings like this:

    QSettings settings("Moose Tech", "Facturo-Pro");


  • @msms said:

    I believe QSettings queries QApplication 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 sense settings("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 instantiate QSettings. Since it is customary to do something like

    int main(int argc, char** argv) {
        QApplication app(argc, argv);
        ...
    }
    

    your QApplication won't exist at the time of your atexit 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 invoking QSettings 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&amp;, 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:

    https://qt.gitorious.org/qt/qt/source/08c0f9cf858e7c2563c8b6c3b121d619989a92ee:src/corelib/io/qsettings.cpp#L2746

    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


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.