rubyqtcrashqtruby

Qt/Ruby Application Crash in Qt::AbstractItemModel::mimeData - How to find and fix the cause?


Recently I wrote a little application using Ruby and Qt. It was my first non-trivial project with qtruby. After some time I managed to translate C++ references and tutorials into working Ruby code, and got the hang of it.

Only when implementing my own drag and drop functionality in QTreeView widgets, I got really stuck. I could isolate the problem to the Qt::AbstractItemModel::mimeData method. After eliminating some other mistakes, I ended up with the following code which somehow caused the application to crash as soon as a drag action occured.

class TreeModel < Qt::AbstractItemModel
  def mimeData(indexlist)
    encodedData = Qt::ByteArray.new("")
    stream = Qt::DataStream.new(encodedData, Qt::IODevice::WriteOnly)  

    indexlist.each do |index|
      if index.column == 0
        if index.isValid
          stream << index.item.mime_data.to_json
        end
      end
    end

    mimeData = Qt::MimeData.new
    mimeData.setData("application/x-tegi.json", encodedData)
    mimeData
  end
end

The crash appeared non-deterministic, a few times the code just worked. The error dump and backtrace did not give me a hint, only that the crash happened inside QApplication::exec.

What is the issue and how can it be fixed?


Solution

  • The C++ prototype for mimeData is :

    QMimeData * QAbstractItemModel::mimeData 
      ( const QModelIndexList & indexes ) const [virtual]
    

    The method returns a pointer to a QMimeData object. My implementation of mimeData was returning a pointer to a local variable. Thus the non-deterministic crashes.

    Once found, fixing the issue was easy. An instance variable would stay alive and keep its value until the next call of mimeData:

      @mimeData = Qt::MimeData.new
      @mimeData.setData("application/x-tegi.json", encodedData)
      @mimeData
    end
    

    Another possibility is to call super and leave the construction and deconstruction to the superclass. This also inherits the default mime data ("application/x-qabstractitemmodeldatalist"):

      mimeData = super
      mimeData.setData("application/x-tegi.json", encodedData)
      mimeData
    end
    

    After having found the issue, it appears trivial to me. Nevertheless I would like to share it, because I wasted too much time with it. The qtruby documentation warns about pointer arguments and mentions some unsupported functions returning uchar pointers, but no word about functions returning pointers to Qt objects. Being lulled by qtruby seamlessly wrapping data types to and fro, I looked so many times over that little asterisk without spotting it.