1
votes

I have a C++ application where I am reading pcap file format and processing usb packets. For each packet, I would like to create a QListWidgetItem to which I am storing some data and then adding it to the QListWidget. Here is where the trouble begins. According to QListWidget documentation, after inserting item :

The list widget will take ownership of the item.

So what I thought is that its on QListWidget to delete all QListWidgetItems. The items are added fine, but when I close my app(I suppose thats when desctructor od QListWidget is called so he is calling desctructor of each QListWidgetItem) I get delete_scalar exception. According to call stack, deletion of some QListWidgetItem triggers it :call stack screen

Snippet of my code (this function is being called for each packet in pcap file and is responsible for creating and adding items):

 void ItemManager::ProcessPacket(QByteArray packetData)
    {
        const unsigned char* packet = (unsigned char*)packetData.data();
        PUSBPCAP_BUFFER_PACKET_HEADER usbh = (PUSBPCAP_BUFFER_PACKET_HEADER)packet;
    
        QListWidgetItem* item = new QListWidgetItem;
    
        //set USBPCAP header to item
        QByteArray usbhArray((const char*)packet, sizeof(USBPCAP_BUFFER_PACKET_HEADER));
        item->setData(dataHolder->USBPCAP_HEADER_DATA, QVariant(usbhArray));
        packet += sizeof(USBPCAP_BUFFER_PACKET_HEADER);
    
        if (usbh->transfer == USBPCAP_TRANSFER_ISOCHRONOUS || usbh->transfer == USBPCAP_TRANSFER_CONTROL) //check for optional header data
        {
            int additionalDataSize = usbh->headerLen - sizeof(USBPCAP_BUFFER_PACKET_HEADER);
            if (additionalDataSize > 0)
            {
                //set additional header data to item
                QByteArray additionalDataArray((const char*)(packet), additionalDataSize);
                item->setData(dataHolder->TRANSFER_OPTIONAL_HEADER, QVariant(additionalDataArray));
                packet += additionalDataSize;
            }
            else
            {
                item->setData(dataHolder->TRANSFER_OPTIONAL_HEADER, QVariant()); //QVariant creates invalid QVariant, later i just need to check with QVariant::isValid()
            }
        }
        else
        {
            item->setData(dataHolder->TRANSFER_OPTIONAL_HEADER, QVariant());
        }
    
        //set leftover data to item
        QByteArray leftoverDataArray((const char*)packet, usbh->dataLength);
        item->setData(dataHolder->TRANSFER_LEFTOVER_DATA, QVariant(leftoverDataArray));
    
        listWidget->insertItem(listWidget->count(), item);
    }

Calling of ProcessPacket function :

void ItemManager::ProcessFile(QString filename, bool liveReading)
{
    if (fileReader.OpenNewFile(filename))
    {
        if (fileReader.ReadFileHeader())
        {
            while (!stopButtonClicked)
            {
                while (!fileReader.EndOfFile())
                {
                    QByteArray packetData = fileReader.GetPacket();
                    if (!pauseButtonClicked)
                    {
                        ProcessPacket(packetData);
                    }
                }

                parent->Refresh();  //this is just calling QCoreApplication::processEvents();

                if (!atBottomOfList)
                {
                    listWidget->scrollToBottom();
                }

                if (liveReading)
                {
                    Sleep(50);
                }
                else
                {
                    return;
                }
            }
        }
    }
}

EDIT

I found out that this problem is happening only when appending to QListWidget through ItemManager class. In my main Q_OBJECT class USB_Packet_Analyzer(which holds QlistWidget that I am appending to) i have slot on_OpenButton_clicked() which looks like this :

void USB_Packet_Analyzer::on_OpenButton_clicked()
{
    QString fil = QFileDialog::getOpenFileName(this, "Select source file", ".", "Pcap files (*.pcap)");
    ItemManager manager(ui.listWidget,this);
    manager.ProcessFile(fil, ui.liveCaptureRadioButton->isChecked());
}

where in ItemManager class constructor looks like this :

ItemManager::ItemManager(QListWidget* listWidget, USB_Packet_Analyzer* parent)
{
    this->stopButtonClicked = false;
    this->pauseButtonClicked = false;
    this->atBottomOfList = false;
    this->listWidget = listWidget;
    this->parent = parent;
    this->dataHolder = DataHolder::GetDataHolder();
}

Now, if I add items in on_OpenButton_clicked() slot and close the app, everything is fine. But when I create ItemManager instance and append items in that class, the error occurs. Could it be that I am not allowed to pass QListWidget* as parameter ?

2
Looks like deletion of the already freed memory. You might want to check, where you explicitly delete a Qt object which is a child of another Qt object.vahancho
@vahancho what Qt objects do you mean ? I have only 1 Q_OBJECT class which i got when I created Qt app. This class has ownership of QListWidget. For adding QListWidgetItems I have another class ItemManager which is responsible for reading pcap files and adding items(it has pointer to QListWidgetItem for adding purposes). ItemManager class is being destroyed after finished reading file, but my main Q_OBJECT class is still alive. I suppose it is being deleted after closing app main window just before the program ends.Peter Lakatoš
Pretty sure that the problematic code is not shown - everything seems fine in what you have posted so far. My suspicion is that you have some other code that is deleting the QListWidget or USB_Packet_Analyzer and then Qt tries to delete it again. Are your storing any QObject derived classes in smart pointers?Dean Johnson

2 Answers

0
votes

You have to create a new item inside your loop. You must not reuse the pointer because no content is copied, only the pointer is stored within the QListWidget

0
votes

To this day I am not completely sure what caused the error, but it was fixed after I modified USBPCAP structs which I were using. They use all kind of stuff like #pragma pack(1) , #pragma pack(push) and so on. It looks like I was missing some of those, which might result in some undefined behaviour while using them.