Command line to compile: c++ -I/usr/local/include/qt5/QtCore -I/usr/local/include/qt5 -fPIC -L/usr/local/lib/qt5 -lQt5Core test.cpp -O0 -g The problematic code (extracted from KDevelop sources): #include <QJsonObject> QJsonObject makeObject() { QJsonObject ret, kplugin; kplugin["EnabledByDefault"] = false; ret["KPlugin"] = kplugin; return ret; } int main() { // works auto p = makeObject()["KPlugin"].toObject(); const auto enabledByDefaultValue = p["EnabledByDefault"]; // segfaults // const auto enabledByDefaultValue = makeObject()["KPlugin"].toObject()["EnabledByDefault"]; const bool enabledByDefault = enabledByDefaultValue.isNull(); return 0; } Changing clang to g++6 doesn't make segfault go away. But compiling on FreeBSD 11 or 10 does make it go away. I've tried using Hex-Rays decompiler to find difference between OK and FAIL versions. Here is the pseudocode for OK version: KPluginMetaData::rawData((KPluginMetaData *)&pluginInfoThis); QString::QString(&string_KPlugin, "KPlugin"); LODWORD(v10) = QJsonObject::operator[](&pluginInfoThis, &string_KPlugin); v25 = v10; v26 = v11; QJsonValueRef::toObject((QJsonValueRef *)&v27); QString::~QString((QString *)&string_KPlugin); QJsonObject::~QJsonObject((QJsonObject *)&pluginInfoThis); QString::QString(&string_EnabledByDef, "EnabledByDefault"); LODWORD(v12) = QJsonObject::operator[](&v27, &string_EnabledByDef); v21 = v12; v22 = v13; QString::~QString((QString *)&string_EnabledByDef); v16 = 1; if ( !(QJsonValueRef::isNull((QJsonValueRef *)&v21) & 1) ) Note that before QJsonValueRef::isNull is called, 3 destructors are run: QString::~QString((QString *)&string_KPlugin); QJsonObject::~QJsonObject((QJsonObject *)&pluginInfoThis); QString::~QString((QString *)&string_EnabledByDef); And here is decompiled code of the FAIL version: KPluginMetaData::rawData((KPluginMetaData *)&pluginInfoThis); QString::QString(&string_KPlugin, "KPlugin"); LODWORD(v10) = QJsonObject::operator[](&pluginInfoThis, &string_KPlugin); v23 = v10; v24 = v11; QJsonValueRef::toObject((QJsonValueRef *)&v25); QString::QString(&string_EnabledByDef, "EnabledByDefault"); LODWORD(v12) = QJsonObject::operator[](&v25, &string_EnabledByDef); v26 = v12; v27 = v13; QString::~QString((QString *)&string_EnabledByDef); QJsonObject::~QJsonObject((QJsonObject *)&v25); QString::~QString((QString *)&string_KPlugin); QJsonObject::~QJsonObject((QJsonObject *)&pluginInfoThis); v16 = 1; if ( !(QJsonValueRef::isNull((QJsonValueRef *)&v26) & 1) ) There 4 destructors are run - 3 from above and additional QJsonObject::~QJsonObject((QJsonObject *)&v25); which is an object that QJsonObject::operator[](&v25, &string_EnabledByDef); operates on. IIUIC, it should be OK to call the destructor early, as Qt manages references to object's data behind the scenes. However, something goes wrong. CFG's of both cases: http://arrowd.name/ok.png http://arrowd.name/fail.png
I'm unfortunately unable to reproduce the issue here. Let me know if there is anything more to test. mfg Tobias
I was able to reproduce this in the jail created from the latest 12.0-CURRENT snapshot: Create a new jail # poudriere -c -j cur12 -v 12.0-CURRENT Build pkg and leave the jail running # poudriere testport -j cur12 -I ports-mgmt/pkg Copy the testcase into the jail # cp test.cpp /usr/local/poudriere/data/.m/cur12-default/ref/root/ Enter it # sudo jexec cur12-sbreeze-n env -i TERM=$TERM /usr/bin/login -fp root Compile the testcase # c++ -I/usr/local/include/qt5/QtCore -I/usr/local/include/qt5 -fPIC -L/usr/local/lib/qt5 -lQt5Core test.cpp -o fail Get a segfault # ./fail Segmentation fault (core dumped) The reversing effort I did was right - when QJsonObject::~QJsonObject is called it dereferences .d field and the count becomes 0. However, returned QJsonValueRef enabledByDefaultValue also holds the same d while it gets deleted. So, when the execution gets to enabledByDefaultValue.isNull(), that .d field is already freed and contains garbage.
The testcase itself is buggy and contains undefined behavior. This was visible for me only because I had MALLOC_PRODUCTION turned off. More details: https://phabricator.kde.org/D12743#268639