Search code examples
qtcrashqdebug

Weird behavior of qDebug() crashing the application


I've been debugging a simple catalogue application and this issue is starting to get the best of me. I want to create a modal dialog, which will receive user input on presented data. I have a simple struct holding the catalogue item data:

struct ItemData {
    int nodeType;
    int nodeID;
    int nodeLevel;
    QString nodeName;
    QString nodeNote;
    QString fileName;
}

Then, a struct to represent the item data in the data input dialog

struct DialogData {
    QString name;
    QString note;
    QString file;
}

Now, the data input dialog is called from the main window's editRec() method:

void MainWindow::editRec()
{
    // model is defined in the main window, getSelectedRowData()
    // fills the struct with data properly
    ItemData md = model->getSelectedRowData(ui->treeView->selectionModel());

    // data, on which the dialog will operate
    DialogData dd;

    dd.name = md.nodeName;
    dd.note = md.nodeNote;
    dd.file = md.fileName;

    // checking whether the data which is being read from the model
    // and being passed to dialog is correct
    // qDebug '<<' operator is overloaded to handle my structs
//    qDebug << md;        // - outputs data properly, then crashes the program
//    qDebug << dd;        // - also, outputs data properly, then crashes the program

    // suspecting the error in the '<<' overload, I tried to output 
    // one field at a time and it works if I if uncomment one 
    // line at a time, but crashes the application if I try to 
    // output all fields in one go.
//  qDebug() << md.nodeType;
//  qDebug() << md.nodeID;
//  qDebug() << md.nodeLevel;
//  qDebug() << md.nodeName;
//  qDebug() << md.nodeNote;
//  qDebug() << md.fileName;

    DataDialog *dialog;

//  dialog's interface and data handling differs depending on 
//  the type of the node it will operate on
    switch (md.nodeType) {
    case NODE_ROOT: {
        dialog = new DataDialog(dlgEditRoot, false, this);
        dialog->setDialogData(dd, NODE_ROOT);
        break;
    }
    case NODE_BRANCH: {
        dialog = new DataDialog(dlgEditBranch, false, this);
        dialog->setDialogData(dd, NODE_BRANCH);
        break;
    }
    }
    dialog->initWidgets();
    if (dialog->exec() == QDialog::Accepted) {   // showing a modal dialog
        // if user changed the data, modifying the model with the new data
        if (dialog->isDataChanged) {             
            dd = dialog->getDialogData();
            switch (md.nodeType) {
            case NODE_ROOT: {
                md.nodeName = dd.name;
                md.nodeNote = dd.note;
                md.fileName = dd.file;
                model->setSelectedRowData(ui->treeView->selectionModel(), md);
                break;
            }
            case NODE_BRANCH: {
                md.nodeName = dd.name;
                md.nodeNote = dd.note;
                md.fileName = dd.file;
                model->setSelectedRowData(ui->treeView->selectionModel(), md);
                break;
            }
            }
        }
    }
    qDebug() << md;    // - both of these output data correctly without any crashes
    qDebug() << dd;    //
    delete dialog;
}

If I comment out the first three qDebug() data dumps, the whole thing works as intended.

I found only two somewhat similar issues on the StackOverflow:

What am I doing wrong here?


Solution

  • The dig I started using Kuba Ober's suggestion led me to a very deep refactoring, almost a complete rewrite, of the whole data structure I was using initially. Although I didn't find the exact cause of the crash I was getting before, I was able to fix the issue.

    Some tips to someone, who might encounter a similar problem. The links I posted in the initial question were actually directly relevant to my problem. On the the first link, Scott 'scm6079' said:

    qDebug creates a fairly significant buffer -- which when stomped on won't crash your program

    I the process of rewriting I was getting exactly this kind of behavior: when my functions did not return a value, qDebug() was 'saving' them from a crash. After forcing all functions to return a value, the crashes stopped.

    Next, if you don't subclass a QObject entity nor use smart pointers, pay extra attention to news to match them with appropriate deletes. Don't create a variable in a condidional branch. If you need to create an object depending on a condidtion, refactor the differing bits out of the constructor into method you will call from conditional branch after creation. While I'm not sure whether is it good coding style or not, it certainly helped me to fix the crash.