Boreet
Boreet

Reputation: 53

Qt QString Q_PROPERTY causing SIGSEGV

I ran into this problem the other day - caught me by surprise and has halted my testing. I'm developing a feature outside of my normal application and I ran into an issue with a Q_PROPERTY that I can't seem to figure out. I've simplified the situation down to bare bones which still replicates the SIGSEGV. My code has a comment switch block that includes or removes an additional Q_PROPERTY "prop2" When I have just one property "prop1" I don't get the seg fault. When I add the additional property "prop2" I get the seg fault. I've included everything - including a dump of gdb. Any help/advice would be most appreciated.

System: Ubuntu 12.04 LTS (the greatest OS on Earth) Qt: 4.8 (as installed with apt-get install qt-sdk)

file: MyObject.hpp

#ifndef MYOBJECT_HPP
#define MYOBJECT_HPP

#include <QObject>

class MyObject : public QObject {
    Q_OBJECT
    Q_PROPERTY(QString prop1 READ prop1 WRITE setProp1 RESET resetProp1)
    //* add/remove comment
    Q_PROPERTY(QString prop2 READ prop2 WRITE setProp2 RESET resetProp2) 
    // end */
private:
    QString m_prop1;
    //* add/remove comment
    QString m_prop2;
    // end */
public:
    MyObject(QObject * parent = 0):QObject(parent){
        resetProp1();
        //* add/remove comment
        resetProp2();
        // end */
    }
    virtual ~MyObject(){ }
    QString prop1() const{
        return m_prop1;
    }
    QString setProp1(const QString& prop1){
        m_prop1 = prop1;
    }
    void resetProp1(){
        setProp1("reset");
    }
    //* add/remove comment
    QString prop2() const{
        return m_prop2;
    }
    QString setProp2(const QString& prop2){
        m_prop2 = prop2;
    }
    void resetProp2(){
        setProp2("reset");
    }
    // end */
};

#endif

file: main.cpp

#include <QApplication>
#include "MyObject.hpp"


int main(int argc, char *argv[]) {
    QApplication app(argc, argv);
    MyObject obj;
    return app.exec();
}

file: CMakeLists.txt

cmake_minimum_required(VERSION 2.8)
project(test)
find_package(Qt4 REQUIRED)
QT4_WRAP_CPP(test_MOC_SOURCES 
    MyObject.hpp
)
include(${QT_USE_FILE})

add_executable(test 
    main.cpp
    ${test_MOC_SOURCES}
)

target_link_libraries(test ${QT_LIBRARIES})

gdb output:

Reading symbols from /home/me/temp/string_seg_test/build/test...done.
(gdb) run
Starting program: /home/me/temp/string_seg_test/build/test 
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
[New Thread 0x7fffe7fc6700 (LWP 9297)]
[New Thread 0x7fffe77c5700 (LWP 9298)]
[New Thread 0x7fffe6354700 (LWP 9299)]

Program received signal SIGSEGV, Segmentation fault.
0x00007ffff6d00bbd in QString::operator=(QString const&) () from /usr/lib/x86_64-linux-gnu/libQtCore.so.4
(gdb) bt
#0  0x00007ffff6d00bbd in QString::operator=(QString const&) () from /usr/lib/x86_64-linux-gnu/libQtCore.so.4
#1  0x0000000000401b43 in MyObject::setProp2 (this=0x7fffffffe11000, prop2=...)
    at /home/me/temp/string_seg_test/src/MyObject.hpp:39
#2  0x0000000000401b7f in MyObject::resetProp2 (this=0x7fffffffe11000)
    at /home/me/temp/string_seg_test/src/MyObject.hpp:42
#3  0x000000000040197b in MyObject::MyObject (this=0x7fffffffe11000, parent=0x0)
    at /home/me/temp/string_seg_test/src/MyObject.hpp:21
#4  0x000000004017ee00 in ?? ()
#5  0x007fffffffe23800 in ?? ()
#6  0x0000010040154b00 in ?? ()
#7  0x000000004021b000 in ?? ()
#8  0x000000007ef92000 in ?? ()
#9  0x000000007ef9b000 in ?? ()
#10 0x0000000060310000 in ?? ()
#11 0x007ffff7d9a9d000 in ?? ()
#12 0x00000000604d2000 in ?? ()
#13 0x007fffffffe23000 in ?? ()
#14 0x0000000000000000 in ?? ()
(gdb) 

Upvotes: 0

Views: 1112

Answers (1)

It's a simple problem. Your setter methods return QString, but you never return anything from those methods. Thus a crash. The setters should have the following signature: void setPropx(const QString &);

Your compiler most likely has warned you about this. Thus, the lesson is: do not ignore compiler warnings. Understand their meaning.

On the other hand, you've left in a lot of irrelevant stuff. Had you been methodically stripping things line-by-line, you would have eventually arrived at a much smaller, single file example. The QObject and application instances are not needed, neither is the indirection of the resetProp(), nor do the getters make any difference.

The final two steps of minimization should have been:

// Step N-1
#include <QString>
class C {
    QString m_prop1, m_prop2;
public:
    C() { setProp1("reset"); setProp2("reset"); }
    QString setProp1(const QString& prop1) { m_prop1 = prop1; }
    QString setProp2(const QString& prop2) { m_prop2 = prop2; }
} c;
int main(int, char **) {
    return 0;
}

// Step N
#include <QString>
class C {
    QString m_prop1;
public:
    C() { setProp1("reset"); setProp1("reset"); }
    QString setProp1(const QString& prop1) { m_prop1 = prop1; }
} c;
int main(int, char **) {
    return 0;
}

By this point you could have probably noticed what was wrong.

Everything should be in a single file. The separate header etc. are just a distraction that makes your question longer. This is what you should have posted :)

Upvotes: 1

Related Questions