Qt6 Read Access Violation from QDockAreaLayout
-
Hi all,
I updated my x86 qt5.15.14 application to qt6.5.2 x64 version. After the update, there is a problem in the start of the program. When I call the show() method of the mainwindow class, access violation error occurs. I could not understand why I am getting an error. I am reading some configuration from an xml file before calling the show method of my mainwindow. I did not change any part of that code but it started to crash. Currently I need help in order to fix the problem.
Error message: Unhandled exception thrown: read access violation.
this->widgetItem-> was 0xFFFFFFFFFFFFFFC7.Stack trace:
-
@JonB I am not sure how I can share a code because it only fails when I call the show() method. it is a derived class from QMainWindow. Also, I could not found the problematic place in the code, I am not sure if it is caused by changing win32 app to x64 or qt version change
-
@Bilal-Can You should provide a minimal, compileable example. Create a simple mainwindow and add a dock widget.
-
Since the application is very huge, I added some part of the code.
This is dock area creation:
m_poNavigationArea=new QDockWidget("navigation area",m_poMainWindow.data()); m_poNavigationArea->setObjectName("navigation_menu"); m_poNavigationArea->setWhatsThis("link here"); m_poNavigationArea->setFeatures(QDockWidget::DockWidgetClosable); m_poNavigationArea->setAllowedAreas(Qt::AllDockWidgetAreas); m_poMainWindow->addDockWidget(Qt::LeftDockWidgetArea, m_poNavigationArea);
Also there 3 similar dockwidgets via calling m_poMainWindow->addDockWidget with Qt::RightDockWidgetArea once and Qt::BottomDockWidgetArea twice.
This is what xml file looks like:
I am reading state and geometry attributes and set them like below:QByteArray oOrgDataState = QByteArray::fromHex(oDataAttribute.toLatin1()); if(!oOrgDataState.isNull()) { m_poMainWindow->restoreState(oOrgDataState);/*lint !e534 (ignore return value)*/ }
Those are the things I am doing
Also in update from qt5 to qt6, I replaced all setMargin(0); calls of QLayout's with setContentsMargins(0, 0, 0, 0); and some classes I did not convert all QRegExp to QRegularExpression and included both <QRegularExpression> and <QtCore5Compat/QRegExp>, but I dont think that they are related with the issue.
I also investigated QDockAreaLayoutItem::skip(), normally it calls like this:
but somehow at some point it shows and it somehow passes the nullptr check and crashes at line 91
-
@Bilal-Can
I don't think others will be able to help without you posting a complete, minimal compilable example illustrating your issue. After all, people use QDockWidget at Qt6 without it crashing on them, so you have to provide something which causes this unusual behaviour else who can guess where the problem will lie? If the state restoration code is relevant/critical, people don't even know what is in the state you are restoring. -
File reading section is like below. I tried to put
const QString RCL_XML_ATT_INT_IDX = "idx"; const QString RCL_XML_ATT_INT_VALUE = "value"; QDomDocument* MauiUtil::XmlReadFile(const QString& roFileName) { QDomDocument* poDomDoc(NULL); try { if (!QFile::exists(roFileName)) { return NULL; } QFile oFile(roFileName); if(!oFile.open(QIODevice::ReadOnly)) { return NULL; } poDomDoc = new QDomDocument; QString oErrorMsg; if(!poDomDoc->setContent(&oFile,&oErrorMsg)) { delete poDomDoc; poDomDoc = NULL; qCritical("MauiUtil::XmlReadFile failed: %s",oErrorMsg.toLocal8Bit().constData()); return NULL; } oFile.close(); return poDomDoc; } catch (...) { qCritical("MauiUtil::XmlReadFile failed"); } if( poDomDoc ) { delete poDomDoc; poDomDoc = NULL; } return poDomDoc; } void MauiUtil::XmlAddIntToParent( QDomElement& roParentElement, const QString& roChildName, const QVector<int32>& roValues ) { int32 sl_size(roValues.size()); QDomDocument o_doc; for(int32 sl_idx(0);sl_idx<sl_size;++sl_idx) { QDomElement o_child_element(o_doc.createElement(roChildName)); if( o_child_element.isNull() ) { continue; } o_child_element.setAttribute(RCL_XML_ATT_INT_IDX,QString("%1").arg(sl_idx)); o_child_element.setAttribute(RCL_XML_ATT_INT_VALUE,QString("%1").arg(roValues.at(sl_idx))); roParentElement.appendChild(o_child_element); } } bool MauiUtil::XmlGetAttrValue( const QDomElement& roElement, const QString& roAttrName, QString& roAttrValue ) { roAttrValue = QString::fromUtf8(roElement.attribute(roAttrName).toLatin1()); if( roAttrValue.isNull() ) { return false; } return true; } void MauiUtil::XmlGetIntFromParent( const QDomElement& roParentElement, const QString& roChildName, QVector<int32>& roValuesResult ) { QString o_value_string; QString o_idx_string; QList<int32> o_idx_list; QList<int32> o_value_list; for(QDomElement o_child_element(roParentElement.firstChildElement(roChildName)); !o_child_element.isNull(); o_child_element = o_child_element.nextSiblingElement(roChildName) ) { if( MauiUtil::XmlGetAttrValue(o_child_element,RCL_XML_ATT_INT_IDX,o_idx_string) && MauiUtil::XmlGetAttrValue(o_child_element,RCL_XML_ATT_INT_VALUE,o_value_string) ) { o_idx_list.append(o_idx_string.toInt()); o_value_list.append(o_value_string.toInt()); } } int32 sl_idx_size(o_idx_list.size()); if( sl_idx_size>0 && sl_idx_size==o_value_list.size() ) { roValuesResult.resize(sl_idx_size); for(int32 sl_idx(0);sl_idx<sl_idx_size;++sl_idx ) { roValuesResult.replace(o_idx_list.at(sl_idx),o_value_list.at(sl_idx)); } } } void MauiUtil::SetTreeViewColumnWidth( QTreeView* poTreeView, QVector<int32>& roWidths ) { if( poTreeView && poTreeView->model() ) { QAbstractItemModel* po_model(poTreeView->model()); int32 sl_model_col_size(po_model->columnCount()); if( !roWidths.isEmpty() && sl_model_col_size==roWidths.size() ) { // make a copy of roWidths // changing one column emits appropriate signal, catching this // signal the array might changed outside when this function // is interrupted QVector<int32> o_widths_copy(roWidths); int32 sl_col_width; for( int32 sl_idx(0);sl_idx<sl_model_col_size;++sl_idx ) { //qDebug() << "col " << sl_idx << " set to width " << o_widths_copy.at(sl_idx); sl_col_width=o_widths_copy.at(sl_idx); if( sl_col_width<0 ) { ResizeColumnToContents(poTreeView, sl_idx); } else { poTreeView->setColumnWidth(sl_idx,sl_col_width); } } } else { // resize column to contents when no column width information is available // or when columns sizes are different //qDebug() << "resize all col to contents"; roWidths.resize(sl_model_col_size); for( int32 sl_idx(0);sl_idx<sl_model_col_size;++sl_idx ) { ResizeColumnToContents(poTreeView, sl_idx); roWidths.replace(sl_idx,poTreeView->columnWidth(sl_idx)); } } } } void MauiUtil::ResizeColumnToContents(QTreeView* poTreeView, int32 slColIdx) { poTreeView->resizeColumnToContents(slColIdx); int columnWidth = poTreeView->columnWidth(slColIdx); if( columnWidth < MinColumnSize ) { poTreeView->setColumnWidth(slColIdx, MinColumnSize); } if( columnWidth > MaxColumnSize ) { poTreeView->setColumnWidth(slColIdx, MaxColumnSize); } }
void C_MainView::ReadSettings() { if(m_poMainWindow.isNull()) { // nothing to restore for, when no window available return; } QDomElement oRootElement(GetSettings()); //qDebug() << "C_MainView::ReadSettings() " << oRootElement.nodeName(); if( oRootElement.isNull() ) { return; } QDomElement oWindow=oRootElement.firstChildElement(RCL_XML_ELEMENT_WINDOW); if( !oWindow.isNull() ) { QString oDataAttribute; if( MauiUtil::XmlGetAttrValue(oWindow,"geometry",oDataAttribute) ) { QByteArray oOrgDataGeometry; oOrgDataGeometry = QByteArray::fromHex(oDataAttribute.toLatin1()); if (!oOrgDataGeometry.isNull()) { m_poMainWindow->restoreGeometry(oOrgDataGeometry);/*lint !e534 (ignore return value)*/ } } if( MauiUtil::XmlGetAttrValue(oWindow,"state",oDataAttribute) ) { QByteArray oOrgDataState; oOrgDataState = QByteArray::fromHex(oDataAttribute.toLatin1()); if(!oOrgDataState.isNull()) { m_poMainWindow->restoreState(oOrgDataState);/*lint !e534 (ignore return value)*/ } } if( MauiUtil::XmlGetAttrValue(oWindow,"navigator",oDataAttribute) && m_poProjectNavigator ) { if( oDataAttribute=="invisible" ) { m_poProjectNavigator->close(); } else { m_poProjectNavigator->show(); } } } m_poMainWindow->setCentralWidget(m_poWorkingArea); }
-
By the way, I have found something
I manupulated the xml file via removing geometry="01d9d0cb00030000fffffffffffffff700000780000004060000046c000000b40000077f000003d300000000020000000780000000000000001d0000077f00000405" attribute. When I remove this, there is no crash. If I add it again, it crashes
<mainview> <window state="000000ff00000000fd00000003000000000000010000000237fc0200000001fb00000016006d00610069006e0076006900650077005f0070006e0100000042000002370000007100ffffff00000001fffffffffffffffffc0200000001fb00000016006d00610069006e0076006900650077005f007700610100000000ffffffff0000000000000000000000030000078000000152fc0100000002fb00000016006d00610069006e0076006900650077005f006300770100000000000001790000000000000000fb00000016006d00610069006e0076006900650077005f006400760100000000000007800000011200ffffff0000067b0000023700000004000000040000000800000008fc000000010000000200000001000000660043005f004d00610069006e0056006900650077003a003a0070006f005f006e00650077005f0074006f006f006c005f00620061007200530069006d006f006300720061006e0065002000530065006e0073006f00720020004d006f00640075006c006500730100000000ffffffff0000000000000000" geometry="01d9d0cb00030000fffffffffffffff700000780000004060000046c000000b40000077f000003d300000000020000000780000000000000001d0000077f00000405" navigator="visible"/> <language selected_action_name="english"/> </mainview>
-
Then don't restore the old window state from Qt5.
-
@Christian-Ehrlicher do you know why it is a problem? Is there some behavior change in Qt6?
-
This can really be a bug. This is scenario:
- Delete geometry tag,
- Open app.exe
- Close app (geometry value is created in the xml)
- Open app.exe (geometry value created in 3rd step is used and successful)
- Maximize the window
- Close app (geometry value is created in the xml)
- Open app.exe => The same crash
-
And again - please provide a minimal, compilable example. Noone will look into your full-blown code and even if you report it to bugreports.qt.io noone will look into it until there is a minimal reproducer.
-
@Christian-Ehrlicher The only thing I can say is I am giving "01d9d0cb0003000000000000fffffff9000005ff00000337000001c0000000ac00000521000002eb000000000200000006000000000000000017000005ff00000337" this value m_poMainWindow->restoreGeometry(oOrgDataGeometry); and then I call m_poMainWindow->show();
this value is actually gathered from m_poMainWindow->saveGeometry()..toHex().constData();
the value I wrote above is the value gathered by this method when the user wanted to save the app settings. Currently I cannot support a minimal app but these are the problematic codes -
I have the exact same problem. After upgrading to Qt6, this standard "store/restore" thing started crashing on me.
-
@Martin-Cmar hi and welcome to devnet,
Please provide a minimal compilable example that shows this issue.
In the mean time, did you try to delete the current saved state and trigger a new cycle ?
-
@SGaist Hi, and thanks for welcome :)
Sadly I am in a similar situation as the other guy in the thread. We are working on a big project and providing a minimal sample is almost impossible at this moment. Though I understand that without it, it's hard to say what's wrong.
Yes, removing the old data and starting fresh solves the issue, but since many users run our software, it's not an ideal solution. However, increasing the version number, that is passed into this API effectively causes the same fresh start on their machines as well, so I guess this should be enough.
Either way though, it kinda proves the point that from Qt5 to Qt6, something got changed and loading the data from previous version leads to some memory corruption, so I still think this should be solved somehow officially.
-
@Martin-Cmar thanks for chiming in. Rather than reducing your application, can you trigger that from a dummy minimal application ?