QPlainTextEdit throwing std::bad_alloc

1.1k views Asked by At

I have a program that runs a least squares fit to some data. This procedure is run in a separate thread and controlled from a dialog box. This dialog box has a QPlainTextEdit that shows fitting updates and a final report.

The dialog was created in Qt Designer, the code is run into QtCreator and my Qt version is 4.8.1.

The problem I am running into is somewhat erratic. When I run the procedure a first time, everything is fine. Then if I run it again, sometimes the program crashes with the message

terminate called after throwing an instance of 'std::bad_alloc' what(): std::bad_alloc The program has unexpectedly finished.

I tracked the problem to a call to the clear() method of a QPlainTextEdit. Here is some code.

// Snippets of the class definition
class QLSQDialog : public QDialog, public Ui_QLSQDialog
{
  Q_OBJECT
public:
  QLSQDialog(QWidget *parent = 0);
  (...)
  void UpdateDisplay(const QString &msg, int iter, double norm);  // Update values of chi, etc on displays
signals:
  void Run();           // Signal to run a LSQ procedure
  (...)
private slots:
  void on_btnRun_clicked();
  (...)
private:
  void Enables(bool running);   // Enable and disable features depending on running state of LSQ fit
  (...)
};


// Snippets of the class implementation

QLSQDialog::QLSQDialog(QWidget *parent) : QDialog(parent)
{
  setupUi(this);          // Set up dialog
  (...)
  txtInfo->clear();  // txtInfo is a QPlainTextEdit created in Designer
  (...)
}

void QLSQDialog::UpdateDisplay(const QString &msg, int iter, double norm)
{
  lblChi->setText(QString::number(norm,'f',12));
  if (iter >= 0) lblIt->setText(QString::number(iter));
  txtInfo->appendPlainText(msg);
}

void QLSQDialog::on_btnRun_clicked()
{
  txtInfo->clear();   // Offending line in second run
  Enables(true);
  emit Run();
}

void QLSQDialog::Enables(bool running)
{
  bool Idle = !running;
  bool HasReport = !txtInfo->document()->isEmpty();
  (...)
  btnReport->setEnabled(Idle && HasReport);
}

txtInfo is the QPlainTextEdit object. I call a txtInfo->clear() when the object is created to show an empty text edit. When I click on a 'Run' tool button its default slot emits a Run signal that will start the new thread. The txtInfo QPlainTextEdit is updated in this thread until it finishes (in fact the thread emits a signal that is caught in the main application that in turn calls the UpdateDisplay).

If I click on the run button a second time, then I get the crash and the error. If I replace txtInfo->clear(), txtInfo->document()->clear(), by txtInfo->setPlainText("") or by txtInfo->document()->setPlainText("") the problem is the same (crash at second execution). Occasionally, but not frequently, I can run a few times (of the order of 10) before crashing.

Finally, if I comment out the txtInfo->clear() line, then I can run the routine as much as I tried (in one test I got tired after running it about 80 times).

My only (almost random) guess is that the problem is somehow related to the update from the thread (which emits a signal that is caught and in turn just calls the UpdateDisplay function). The reason I think so is that if I comment out the signals and just create a new button to call the UpdateDisplay with some bogus information, everything is fine.

A qApp->processEvents() before the offending line has no effect.

I am stuck here. Any ideas are welcome. For instance, is there any test I can do to verify that calling the clear() method is ok?

1

There are 1 answers

4
rpsml On

I finally tracked this problem down to a nasty memory leak in my code. I "repaired" the code but I am still a little bit puzzled by why the problem was happening.

Basically, I was creating a large vector<double> somewhere and passing its address to a function that called for a vector<double> * variable. The problem was that the original vector ceased to be before the function finished working with. Classic dumb mistake. Probably the QPlainTextEdit document was allocating space in the area where the vector<double> used to be: erratic behavior expected. But I would not expect a crash.

The vector was "read-only". The function using it, only read the values and made calculations stored somewhere else. Let's now assume that the plain text creates something in the memory previously addressed by the vector<double>. In this case, when I QPlainTextEdit::clear() the plain text document, the values previously pointed by the vector change and I would expect the calculations to be non sense. I would also accept a crash when the function access the now deceased pointer to vector<double>. But I would not expect the program to crash when I clear the text, which after all is a valid pointer.

Anyway, if anybody has a though, I'd be curious to know why the crash happens. But otherwise, the problem is gone once the leak was repaired. And of course, knowing the reason is absolutely no excuse to not repair the leak.