1

一天多来我一直试图找到这个错误,我开始发疯了......我已经重新编写并仔细检查了拖放代码,但无济于事。

它发生在主 Qt 事件循环 a.exec() 中,来自 valgrind 的堆栈跟踪如下所示。它有时会在 QMutex::Lock() 上崩溃(我只使用一个 QThread(主 qt 事件循环),所有其他线程都包含在后端并且是安全的)

由于我自己使用鼠标花了一个多小时才出现这个错误,所以我编写了一个函数来移动鼠标关于按下、释放、单击、双击。这会导致错误在大约十分钟内发生。

我会发布一些代码,但它们是几千行用于拖放的东西(除了这个烦人的错误之外,它完美地工作)

拖动可以发生在两种类型的项目中,并且两者基本相同。在鼠标移动事件中,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();
  }
}

这是创建拖动对象的地方之一,还有 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

0

Qt::DropAction dropAction = _drag->exec();这是您的代码可能崩溃的行。我没有完全阅读您的代码,但我假设在拖动小部件后,您正在使用 deleteLater() 函数删除原始小部件。如果是这种情况,那么对于窗口平台 tit 将工作正常,因为_drag->exec()会阻止事件,如果它是 mac 或 Linux,它不会阻止事件。这样,_drag->exec()在执行事件时获取空指针的事件。

我知道deleteLater()当控件返回事件循环时将删除对象时执行此操作。

一般来说,deleteLater() 是在 _drag->exec() 完成之前执行的。

于 2019-06-27T22:58:10.083 回答