私はこのバグを 1 日以上見つけようとしてきましたが、気が狂い始めています...コードを書き直して、ドラッグ アンド ドロップのコードを詳しく調べましたが、役に立ちませんでした。
これは、メインの Qt イベント ループ a.exec() で発生し、valgrind からのスタック トレースが以下に示されています。QMutex::Lock() でクラッシュすることがあります (私は 1 つの QThread (メインの qt イベント ループ) のみを使用します。他のすべてのスレッドはバックエンドに含まれており、安全です)
自分でマウスを使ってバグが表示されるまでに 1 時間以上かかったので、マウスを押す、離す、クリックする、ダブルクリックするといった動作を行う関数を作成しました。これにより、バグが約 10 分以内に発生します。
いくつかのコードを投稿したいと思いますが、それらはドラッグ アンド ドロップ用に数千行あります (この厄介なバグとは別に完全に機能します)。
ドラッグは 2 種類のアイテムで発生する可能性があり、基本的にはどちらも同じです。マウス移動イベントで、drag->exec() が呼び出されます。
サブクラス化された MIME データを使用して、必要なものを含めることができます。
どんな助けでも素晴らしいでしょう...
Invalid read of size 8
in main in Src/Program/main.cpp:77
Address 0x40 is not stack'd, malloc'd or (recently) free'd
1: QCoreApplication::postEvent(QObject*, QEvent*, int) in /usr/lib/x86_64-linux-gnu/libQtCore.so.4.8.1
2: /usr/lib/x86_64-linux-gnu/libQtGui.so.4.8.1
3: QApplication::x11ClientMessage(QWidget*, _XEvent*, bool) in /usr/lib/x86_64-linux-gnu/libQtGui.so.4.8.1
4: QApplication::x11ProcessEvent(_XEvent*) in /usr/lib/x86_64-linux-gnu/libQtGui.so.4.8.1
5: /usr/lib/x86_64-linux-gnu/libQtGui.so.4.8.1
6: g_main_context_dispatch in /lib/x86_64-linux-gnu/libglib-2.0.so.0.3200.3
7: /lib/x86_64-linux-gnu/libglib-2.0.so.0.3200.3
8: g_main_context_iteration in /lib/x86_64-linux-gnu/libglib-2.0.so.0.3200.3
9: QEventDispatcherGlib::processEvents(QFlags<QEventLoop::ProcessEventsFlag>) in /usr/lib/x86_64-linux-gnu/libQtCore.so.4.8.1
10: /usr/lib/x86_64-linux-gnu/libQtGui.so.4.8.1
11: QEventLoop::processEvents(QFlags<QEventLoop::ProcessEventsFlag>) in /usr/lib/x86_64-linux-gnu/libQtCore.so.4.8.1
12: QEventLoop::exec(QFlags<QEventLoop::ProcessEventsFlag>) in /usr/lib/x86_64-linux-gnu/libQtCore.so.4.8.1
13: QCoreApplication::exec() in /usr/lib/x86_64-linux-gnu/libQtCore.so.4.8.1
14: main in
主要:
QApplication a(argc, argv);
if (testing)
{
UnitTest::RunAllTests();
return 0;
}
MainWindow w(debug, testing);
w.show();
w.InitialiseGUI();
return a.exec(); <- line 77
ドラッグ オブジェクトの作成時:
void ElementItem::mouseMoveEvent(QMouseEvent * event)
{
if
(
(event->buttons() & Qt::LeftButton) &&
((event->pos() - _drag_start_position).manhattanLength() > DRAG_START_DISTANCE)
)
{
_control_and_status->_drag_control_object->NotifyDragStarted();
try
{
// Ensure that if something goes wrong and old widget does not get deleted.
// create a new drag object
_drag = new QDrag(this);
// create a custom mime type (subclass of QMimeType)
WidgetMimeType *mimeData = new WidgetMimeType;
ChainWidgetBase * base_widget = LoadElementAndWidget();
// Set the widget as this object
if (base_widget)
{
mimeData->_widget = (QWidget *) base_widget;
mimeData->_delete_on_failure = true;
mimeData->_widget_deletion_required = &_widget_deletion_required;
}
else
{
delete _drag;
_drag = NULL;
throw GeneralException(ErrorReporting::ERROR_IN_DROPPABLE_CONTAINER, "Null widget");
}
_drag->setMimeData(mimeData);
Qt::DropAction dropAction = _drag->exec();
}
catch(...)
{
}
DragStopped();
}
}
これは、ドラッグ オブジェクトが作成される場所の 1 つです。別のことを行う場所がさらに 3 つありますが、同じ方法を使用します。
サブクラス化された MIME データ:
#pragma once
#include <QtGui>
class WidgetMimeType : public QMimeData
{
public:
WidgetMimeType():
_widget(NULL),
_delete_on_failure(false),
_deletion_required_dummy(false),
_widget_deletion_required(&_deletion_required_dummy)
{
}
~WidgetMimeType()
{
}
QWidget * _widget;
bool _delete_on_failure;
bool _deletion_required_dummy;
bool * _widget_deletion_required;
};
編集: QT ソース、クラッシュの場所を追加しました:
void QCoreApplication::postEvent(QObject *receiver, QEvent *event, int priority)
{
if (receiver == 0) {
qWarning("QCoreApplication::postEvent: Unexpected null receiver");
delete event;
return;
}
QThreadData * volatile * pdata = &receiver->d_func()->threadData;
QThreadData *data = *pdata; <--- CRASHES HERE
if (!data) {
// posting during destruction? just delete the event to prevent a leak
delete event;
return;
}
// lock the post event mutex
data->postEventList.mutex.lock();
// if object has moved to another thread, follow it
while (data != *pdata) {
data->postEventList.mutex.unlock();
data = *pdata;
if (!data) {
// posting during destruction? just delete the event to prevent a leak
delete event;
return;
}
data->postEventList.mutex.lock();
}
クラッシュは上記の行で発生し、<---- CRASH HERE. これは、ポインターの逆参照によるものです。これは、何が起こっているかを判断するのに十分な情報ですか?