1

私はこのバグを 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. これは、ポインターの逆参照によるものです。これは、何が起こっているかを判断するのに十分な情報ですか?

4

1 に答える 1