由于在Qt中拖放而导致未知的间歇性崩溃

时间:2013-02-13 15:22:05

标签: c++ qt crash valgrind

我一直试图找到这个错误超过一天了,我开始疯了......我已经重新编写并仔细检查拖放代码无效。

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

由于虫子花了一个多小时自己出现鼠标,我写了一个功能,可以让鼠标按下,释放,点击,双击。这导致错误在大约十分钟内发生。

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

拖动可以在两种类型的项目中发生,并且两者基本相同。在鼠标移动事件中,调用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个做不同的事情,但使用相同的方法

亚模糊哑剧数据:

#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();
    }

崩溃发生在上面显示的行上,其中显示&lt; ---- CRASH HERE。它取决于引用指针。这是否足以确定发生了什么?

1 个答案:

答案 0 :(得分:0)

Qt::DropAction dropAction = _drag->exec();,这是您的代码可能会崩溃的行。我没有完全阅读您的代码,但是我假设拖动小部件后,您将使用deleteLater()函数删除原始小部件。如果在这种情况下,那么由于_drag->exec()会阻止事件,因此对于Windows平台tit来说会很好用,如果是mac或Linux,则不会阻止事件。这样,_drag->exec()事件在执行事件时就获得了空指针。

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

通常,deleteLater()在_drag-> exec()完成之前执行。