App Crash C++ Runtime Library



  • I'm running this small app to read some sensors throughout an Arduino board, the problem is if i move too much the window around and play with it i get a C++ Runtime Library crash either using common Qt widgets or Qwt widgets as follows:
    Microsoft Visual C++ Runtime Library
    This application has requested the runtime to terminate it in a unsual way.
    Please contact the application's support team for more information.

    Plus it gets a little bit laggy when i open the port and start reading from the board, Why is that?
    This are my files:
    .pro

    QT       += core gui serialport
    
    greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
    
    TARGET = EMS-ver2TEST
    TEMPLATE = app
    
    
    SOURCES += \
        main.cpp \
        puertoserie2.cpp \
        widget.cpp
    
    HEADERS  += \
        puertoserie2.h \
        widget.h
    
    QMAKE_CXXFLAGS += -std=gnu++14
    

    Headers:
    puertoserie2.h

    #ifndef PUERTOSERIE2_H
    #define PUERTOSERIE2_H
    
    #include <QObject>
    #include <QWidget>
    #include <QSerialPort>
    #include <QByteArray>
    #include <QVector>
    #include <QPushButton>
    
    class PuertoSerie2 : public QWidget{
      Q_OBJECT
    
    public:
      explicit PuertoSerie2(QWidget *parent = nullptr);
    
    private Q_SLOTS:
      // Conecta con el dispositivo transmisor
      void conexion();
    
      // Lleva a cabo una lectura del vector de informacion entrante
      void leerPlaca();
    
    Q_SIGNALS:
      void SENSOR_A(int);
      void SENSOR_B(int);
      void SENSOR_C(int);
      void SENSOR_D(int);
    
    private:
      void emiteValor();
    
      char banderaEstado(QByteRef);
    
      void estado(char, char);
    
      void setValorSensores();
    
      int refactorizar(QByteArray);
    
      // Estado del boton
      int mPuertoEstado;
    
      // Numero del sensor a leer o modificar
      int mComa;
    
      QSerialPort *mPlaca;
    
      // Informacion de los sensores en arreglos para un  manejo mas compacto
      QVector<QByteArray> mSensorList;
      QVector <int> mSensorValor;
    
      // Buffer de entrada
      QByteArray mBuffer;
    
      // Puerto de la PC
      QString mPuerto;
    
      // Boton que establece la conexion
      QPushButton *mBoton;  
    };
    
    #endif // PUERTOSERIE2_H
    
    

    widget.h

    #ifndef WIDGET_H
    #define WIDGET_H
    
    #include <QWidget>
    #include <QDial>
    
    class Widget : public QWidget{
        Q_OBJECT
    public:
        Widget(QWidget *parent = 0);
        ~Widget();
    private:
        QWidget *crearDial(QDial *);
    };
    
    #endif // WIDGET_H
    
    

    Sources:
    puertoserie2.cpp

    #include "puertoserie2.h"
    #include <QMessageBox>
    #include <QBoxLayout>
    #include <QDebug>
    
    PuertoSerie2::PuertoSerie2(QWidget *parent) : QWidget(parent){
      mComa = 0;
      mPuertoEstado = 0;
      mPuerto = "COM3";
      mBuffer = "";
      mSensorList.push_back(QByteArray());
      qDebug() << "Vector de QByteArray" << mSensorList.at(0);
      mSensorValor.push_back(0);
      qDebug() << "Vector de double" << mSensorValor.at(0);
    
      mBoton = new QPushButton("Abrir Puerto", this);
    
      QHBoxLayout *layout = new QHBoxLayout(this);
      layout->addWidget(mBoton);
      layout->addStretch();
    
      connect(mBoton, SIGNAL(clicked()), this, SLOT(conexion()));
     }
    
    char PuertoSerie2::banderaEstado(QByteRef buffer){
      // 'a' = 42 (asterisco, inicio de cadena)
      // 'b' = 44 (coma, separador)
      // 'c' >= 48 (informacion, contenido)
    
      int var = (int)buffer;
    
      if(var == 42){
        return 'a';
      } else if(var == 44){
        return 'b';
      } else if(var >= 48){
        return 'c';
      }
    
      return 'd';
    }
    
    void PuertoSerie2::estado(char bandera, char byte){
      switch (bandera) {
        // El estado a se supone que limpia los valores enteriores del vector
        // para introducir las nuevas lecturas
        case 'a':
          qDebug() << "\n----------Caso 'a' disparado: " << byte;
          qDebug() << "\nTam de los vectores: " << mSensorList.size() <<
                      "| " << mSensorValor.size();
          qDebug() << "\nTam de coma: " << mComa;
    
          for(int i = 0; i < mSensorValor.size(); ++i){
            mSensorValor[i] = 0.0;
          }
          for(int i = 0; i < mSensorList.size(); ++i){
            mSensorList[i].clear();
          }
    
          mComa = 0;
        break;
    
        // El estado es un separador, aumenta el lugar del vector
        case 'b':
         qDebug() << "\n----------Caso 'b' disparado: " << byte;
         qDebug() << "\nTam de los vectores: " << mSensorList.size() <<
                     "| " << mSensorValor.size();
         qDebug() << "\nTam de coma: " << mComa;
         emiteValor();
         mSensorValor.push_back(0);
         mSensorList.push_back(QByteArray());
         ++mComa;
         qDebug() << "\nAcciones llevadas a cabo";
         qDebug() << "\nTam de los vectores: " << mSensorList.size() <<
                     "| " << mSensorValor.size();
         qDebug() << "\nTam de coma: " << mComa;
        break;
    
        // Tenemos informacion y la signamos al posicion actual de la coma
        case 'c':
         qDebug() << "\n----------Caso 'c' disparado: " << byte;
         qDebug() << "Coma actual: " << mComa;
         qDebug() << "\nTam de los vectores: " << mSensorList.size() <<
                     "| " << mSensorValor.size();
         mSensorList[mComa] += byte;
        break;
    
        default:
         qDebug() << "\n%%%%%%%%%%Final de la Cadena";
         qDebug() << "\nTam de los vectores: " << mSensorList.size() <<
                     "| " << mSensorValor.size();
         emiteValor();
         mBuffer.clear();
    
         while(mSensorList.size() > 1){
             mSensorList.pop_back();
         }
    
         while(mSensorValor.size() > 1){
             mSensorValor.pop_back();
         }
        break;
        }
    }
    
    void PuertoSerie2::conexion(){
      if (mPuertoEstado == 0){
    
        mPlaca = new QSerialPort(this);
        mPlaca->setPortName(mPuerto);
        mPlaca->open(QIODevice::ReadWrite);
    
        if(mPlaca->isOpen() == false){
    
    	 QMessageBox::information(this, "Estado",
    	 "Error al Abrir el puerto: " + mPuerto);
    
        } else {
    
    	 mPlaca->setBaudRate(QSerialPort::Baud9600);
    	 mPlaca->setStopBits(QSerialPort::OneStop);
    	 mPlaca->setParity(QSerialPort::NoParity);
    	 mPlaca->setDataBits(QSerialPort::Data8);
    	 mPlaca->setFlowControl(QSerialPort::NoFlowControl);
    
    	 connect(mPlaca, SIGNAL(readyRead()), this, SLOT(leerPlaca()));
    
    	 mBoton->setText("Cerrar Puerto");
    	 QMessageBox::information(this, "Estado",
    	 "Puerto: " + mPuerto + " Abierto");
    	 mPuertoEstado = 1;
    
        }
      } else if (mPuertoEstado == 1){
    
        mPlaca->close();
        mPlaca->destroyed();
        mPuertoEstado = 0;
        mBoton->setText("Abrir Puerto");
        QMessageBox::information(this, "Estado",
        "Puerto: " + mPuerto + " Cerrado");
    
      }
    }
    
    void PuertoSerie2::leerPlaca(){
    
      mBuffer = mPlaca->readAll();
    
      qDebug() << "\n>>>>>>>> Informacion de entrada: " << mBuffer;
    
      for(int i = 0; i < mBuffer.size(); ++i){
        estado(banderaEstado(mBuffer[i]), mBuffer.at(i));
      }
    }
    
    int PuertoSerie2::refactorizar(QByteArray byte){
      // Convierte el valor de binario a un doble usable
    //  qDebug() << "\nRefactorizando: " << byte;
    
      QString cadena = byte;
      int i = cadena.toInt();
    //  qDebug() << "\nRefactorizado: " << i;
      return i;
    
    }
    
    void PuertoSerie2::setValorSensores(){
      qDebug() << "\nSeteando Valores...";
      for(int i = 0; i < mSensorValor.size(); ++i){
        mSensorValor[i] = refactorizar(mSensorList.at(i));
      }
    }
    
    void PuertoSerie2::emiteValor(){
        setValorSensores();
    
        qDebug() <<"\nValores: " << mSensorValor.at(mComa);
        switch(mComa){
    
        case 0:
            emit SENSOR_A(mSensorValor.at(mComa));
        break;
    
        case 1:
            emit SENSOR_B(mSensorValor.at(mComa));
        break;
    
        case 2:
            emit SENSOR_C(mSensorValor.at(mComa));
        break;
    
        case 3:
            emit SENSOR_D(mSensorValor.at(mComa));
        break;
        }
    
    }
    

    widget.cpp

    #include "widget.h"
    #include "puertoserie2.h"
    #include <QDial>
    #include <QBoxLayout>
    #include <QLabel>
    #include <QFont>
    
    Widget::Widget(QWidget *parent) : QWidget(parent){
        PuertoSerie2 *port = new PuertoSerie2;
    
        QDial *dial = new QDial;
        connect(port, SIGNAL(SENSOR_A(int)), dial, SLOT(setValue(int)));
        QWidget *dialWidget = crearDial(dial);
    
        QDial *dialA = new QDial;
        connect(port, SIGNAL(SENSOR_B(int)), dialA, SLOT(setValue(int)));
        QWidget *dialAWidget = crearDial(dialA);
    
        QDial *dialB = new QDial;
        connect(port, SIGNAL(SENSOR_C(int)), dialB, SLOT(setValue(int)));
        QWidget *dialBWidget = crearDial(dialB);
    
        QDial *dialC = new QDial;
        connect(port, SIGNAL(SENSOR_D(int)), dialC, SLOT(setValue(int)));
        QWidget *dialCWidget = crearDial(dialC);
    
        QHBoxLayout *mainLayout = new QHBoxLayout(this);
        mainLayout->addWidget(dialWidget);
        mainLayout->addWidget(dialAWidget);
        mainLayout->addWidget(dialBWidget);
        mainLayout->addWidget(dialCWidget);
        mainLayout->addWidget(port);
    
        this->setLayout(mainLayout);
    }
    
    Widget::~Widget(){
    
    }
    
    QWidget *Widget::crearDial(QDial* dial){
        int min = 0;
        int max = 100;
    
        dial->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
        dial->setMinimum(min);
        dial->setMaximum(max);
    
        QFont font;
        font.setBold(true);
    
        QLabel *label = new QLabel;
        label->setAlignment(Qt::AlignHCenter);
        label->setFont(font);
    
        connect(dial, SIGNAL(valueChanged(int)), label, SLOT(setNum(int)));
        label->setNum(dial->value());
    
        QVBoxLayout *dialLayout = new QVBoxLayout;
        dialLayout->addWidget(dial);
        dialLayout->addWidget(label);
    
        QWidget *box = new QWidget;
        box->setLayout(dialLayout);
        return box;
    }
    
    

    main.cpp

    #include "widget.h"
    #include <QApplication>
    
    int main(int argc, char *argv[]){
        QApplication a(argc, argv);
        Widget w;
        w.show();
    
        return a.exec();
    }
    


  • Hi @onimusha,

    There's a few suspicious things that could be causing your problems. Let's start with a couple of the ones that stand out to me.

    It seems that PuertoSerie2::leerPlaca is not checking the validity of the PuertoSerie2::mPlaca member before dereferencing it. I can see that your code logic would normally never expect it to be called without being initialised first, but as its connected to a signal, you can't guarantee the order of the events that destroy and use mPlaca (a quick validity check is always advisable anyway).

    Also, the way PuertoSerie2::conexion destroys mPlaca looks risky to me... specifically, the mPlaca->destroyed(); call is (probably) bad - QObject::destroyed is a signal, and probably should not be called this way (at best, it will be ignored, at worst, it will put the object in a very unintended state).

    A better approach might be something like:

    void PuertoSerie2::conexion(){
        ...
        mPlaca->close();
        mPlaca->deleteLater();
        mPlaca = nullptr;
        ...
    }
    

    Then in PuertoSerie2::leerPlaca, check if mPlace is null or not (and/or disconnect the slot prior to the deleteLater call above). As the code stands currently, leerPlace could be calling readAll on a QSerialPort object on which you have invoked QObject::destroyed (which may well have corrupted the object).

    So try fixing up the management of your PuertoSerie2::mPlace pointer's lifecycle, and see if that helps.

    Cheers.



  • Hi @Paul-Colby,
    Changing a few lines:

    else if (mPuertoEstado == 1){
    
        mPlaca->close();
        mPlaca->deleteLater();
        mPlaca = nullptr;
        mPuertoEstado = 0;
        mBoton->setText("Abrir Puerto");
        QMessageBox::information(this, "Estado",
        "Puerto: " + mPuerto + " Cerrado");
    
      }
    

    and:

    if(mPlaca != nullptr){
    
        mBuffer = mPlaca->readAll();
    
        qDebug() << "\n>>>>>>>> Informacion de entrada: " << mBuffer;
    
        for(int i = 0; i < mBuffer.size(); ++i){
          estado(banderaEstado(mBuffer[i]), mBuffer.at(i));
        }
      }
    

    as you said makes thinks even worse. the whole thing crashes in 2 sec, i cannot think how to manage that king of menber life cicle because this reaches my level of understanding about C++ / Qt / System platform



  • @Paul-Colby
    One thing to notice is that the same code runs smoother on my IBM thinkpad Z60t under Lubuntu 14.04. Just wonder why....


  • Moderators

    You should run a debug build through the debugger to see where it crashes



  • Hello @jsulm i did that alrdy and nothing pops up when the crash happens



  • @jsulm I just want to know if there is something wrong in my code that could cause the crash besides my fuzzy logic to write code and algorithms. Other than that i think its my windows 7 machine.



  • I think the problem lies in windows asynchronous tasks...... not being able to read the buffer properly while taking care of other tasks like repainting the window i'm currently moving, as a result my QVector goes out of index.


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.