std::string destructor crashing in Release when using ::toStdString methods
-
I am not trying to log the binary portion of the payload. The QByte array is an array of chars from a socket read. The front portion of the array is string data representing the header of the message. The following line:
QString to_log(msg_in.mid(0, (msg_in.indexOf("aop\0"))));
Isolates the string portion, starting at position zero, continuing until the first instance of "aop\0", which denotes the start of the binary payload. The resulting QString contains just the header, which is string data. It is this portion that is being logged The binary payload is handled farther downstream.
-
In my original post, I pointed out that this has been impossible to debug thus far, and believe me I tried for quite a few days before my first post. The call stack is unusable as the crash occurs deep within Qt and and Windows libraries for which I have nothing but disassembly code to look at. The call to
_tidy()
in thestd::string
is what's crashing indicating a stack/heap corruption, and the crash report supports this.Here is another example of a crash that WAS occurring, which is much more straightforward:
CommunicationHandler::CommunicationHandler(QObject* owner_in) : QObject(owner_in) { QString cur_dir("../output/"); dna::FilenameTimestamp start_timestamp; std::string filename = start_timestamp.getTimestampedFilename( cur_dir.toStdString(), "TAPDisplayMessagingLog", ".xml"); TapMessagingLogger::instance()->openLogFile(filename); }
In the above case, the crash was occurring in the call to
::getTimestampedFilename()
This was due to the destruction of the temporarystd::string
created from the call tocur_dir.toStdString()
in the argument listI modified the code to eliminate the temporary variable thinking something might be wrong there:
CommunicationHandler::CommunicationHandler(QObject* owner_in) : QObject(owner_in) { QString cur_dir("../output/"); std::string dir_str = cur_dir.toStdString(); dna::FilenameTimestamp start_timestamp; std::string filename = start_timestamp.getTimestampedFilename(dir_str , "TAPDisplayMessagingLog", ".xml"); TapMessagingLogger::instance()->openLogFile(filename); }
In this case, the crash was occurring when the constructor went out of scope. Again, the crash was occurring in the
_tidy()
method ofstd::string
while trying to destroydir_str
. I modified the code once again, eliminating the initial QString altogether:CommunicationHandler::CommunicationHandler(QObject* owner_in) : QObject(owner_in) { std::string dir_str = "../output/"; dna::FilenameTimestamp start_timestamp; std::string filename = start_timestamp.getTimestampedFilename(dir_str , "TAPDisplayMessagingLog", ".xml"); TapMessagingLogger::instance()->openLogFile(filename); }
And the crash was resolved. This is not a code problem. There is some insidious problem with my compiled code and the precompiled binaries installed with the Qt Installer. I am in the process of trying to compile the Qt Libraries from source using my compiler to see if this resolves the problem
-
Hi,
I created a sample program:
#include <QFileDialog> #include <string> Widget::Widget(QWidget *parent) : QWidget(parent), ui(new Ui::Widget) { ui->setupUi(this); } Widget::~Widget() { delete ui; } void Widget::on_pushButton_clicked() { std::string my_str = ui->lineEdit->text().toStdString(); qDebug("Hello %s", my_str.c_str()); } void Widget::on_lineEdit_textChanged(const QString &arg1) { ui->pushButton->setDisabled(arg1.isEmpty()); } void Widget::on_toolButton_clicked() { QString fileName = QFileDialog::getOpenFileName( this, tr("Choose a file"), "."); if(!fileName.isEmpty()) ui->lineEdit->setText(fileName); }
In a form I use a
QFileDialog
to choose a file from the file-system and when a button is clicked I convert the fileName to astd::string
and print it to thestdout
.
I run this program without crash.I'm on OS X with Qt 5.4.1.
In your function use the the conversion withtoStdString()
and comment the following lines; verify is the crash is still thereCommunicationHandler::CommunicationHandler(QObject* owner_in) : QObject(owner_in) { QString cur_dir("../output/"); std::string dir_str = cur_dir.toStdString(); // dna::FilenameTimestamp start_timestamp; // std::string filename = // start_timestamp.getTimestampedFilename(dir_str , // "TAPDisplayMessagingLog", // ".xml"); // TapMessagingLogger::instance()->openLogFile(filename); }
-
I posted almost the exact same pseudocode in my original post, and yes I have already tried this in code, as I alluded to in a follow-up post. On my system it crashes, which is a Windows system. I don't have this problem on the Mac. This is a problem (for me) on the Windows platform using MSVC2010.
-
Qt and your code are probably not compiled with the same STL version. Something like this:
http://stackoverflow.com/questions/14090341/difference-in-byte-size-of-stl-containers-in-visual-studio-2010-and-2012 -
@sandy.martel23 said:
I recompiled the Qt Library from source using the same compiler and that did not solve the problem. I am trying different C++11 options now to see if that's implicated
-
I think I might be on the right track to figuring out what's going on. My project builds three executables. I recreated the same code that causes a crash in the problem executable in another of the remaining executables and the crash is not reproducible there. This leads me to suspect there is an alignment issue or something else that is affecting ONLY this one executable.
-
My previous assertion that only one executable had the problem was false. I quickly mocked up the following in the main method of all three executables and got similar results:
using std::string; int main(int argc, char *argv[]) { { QString temp("blah"); string temp_str = temp.toStdString(); std::cout << temp_str << std::endl; std::cout << "blah2" << std::endl; string temp_str2 = temp_str; temp_str2.append("a"); std::cout << temp_str2 << std::endl; }
The output:
£♫ â─♦â° un §$ blah2 £♫ â─♦â° un §$a
As you can see, the string is already junk when it's streamed to
std::cout
but looks fine in the watch list in the debugger. The string literal outputs fine. The copying oftemp_str
totemp_str2
does not crash, nor does the append call, as evidenced by the last line. When the code goes out of scope, the crash occurs as normal. This suggests that even the original call totemp.toStdString()
resulted in what looked like a valid string, but thestd::cout
results and the copy output clearly shows that something is wrong even before we go out of scope. -
Do you have MSVC10 service packs installed?
I remember MSVC10 in 64 bit had a nasty bug which took microsoft about a year to fix. -
SP1 should have solved the problem I mentioned, so it is not it.
-
@DRoscoe said:
I recompiled the Qt Library from source using the same compiler and that did not solve the problem.
But it seems that your still mixing debug and release STL object.
sizeof( debug std::string ) != sizeof( release std::string ). -
Hi @DRoscoe,
- Did you run your RELEASE program inside the IDE, or by double-clicking the executable?
- Could you post the contents of your PATH?
QString temp("blah"); string temp_str = temp.toStdString(); std::cout << temp_str << std::endl; std::cout << "blah2" << std::endl; string temp_str2 = temp_str; temp_str2.append("a"); std::cout << temp_str2 << std::endl;
The output:
£♫ â─♦â° un §$
blah2
£♫ â─♦â° un §$aThere's something very wrong indeed. What happens when you:
- Print through qDebug() instead of std::cout?
- Print the QString itself?
- Do an indirect conversion that bypasses QString::toStdString()?
QString temp; QByteArray arr = temp.toUtf8(); std::string temp_str(arr.data()); qDebug() << temp; qDebug() << arr; qDebug() << temp_str.c_str();
At this point, I'll try anything!
One other thing I can think of is to install the MinGW version of Qt and use that to build you project. The binaries are very different, and might free you from the strange string issue.
-
I modified the code as suggested:
{ QString temp("blah"); qDebug() << "QString: " << temp; string temp_str = temp.toStdString(); qDebug() << "TEMP_STR: " << temp_str.c_str(); qDebug() << "blah2"; string temp_str2 = temp_str; temp_str2.append("a"); qDebug() << temp_str2.c_str(); }
In this case, the copy from
temp_str
totemp_str2
caused the crash. The output from what did execute:QString: "blah" TEMP_STR: blah2
In both tests, I ran from the IDE, since the behavior is easily reproducible. However, I also ran it from the command line with the same results. Here is the contents of my PATH variable:
C:\Users\roscoe.NASALAB>echo %PATH% C:\Python27\;C:\Python27\Scripts;C:\Perl64\site\bin;C:\Perl64\bin;C:\Program Fil es (x86)\IBM\RationalSDLC\common;C:\Program Files (x86)\Intel\iCLS Client\;C:\Pr ogram Files\Intel\iCLS Client\;C:\Windows\system32;C:\Windows;C:\Windows\System3 2\Wbem;C:\Windows\System32\WindowsPowerShell\v1.0\;C:\Program Files\Intel\Intel( R) Management Engine Components\DAL;C:\Program Files (x86)\Intel\Intel(R) Manage ment Engine Components\DAL;C:\Program Files\Intel\Intel(R) Management Engine Com ponents\IPT;C:\Program Files (x86)\Intel\Intel(R) Management Engine Components\I PT;c:\Program Files (x86)\Microsoft SQL Server\100\Tools\Binn\;c:\Program Files\ Microsoft SQL Server\100\Tools\Binn\;c:\Program Files\Microsoft SQL Server\100\D TS\Binn\;C:\Program Files (x86)\IBM\RationalSDLC\ClearCase\bin;C:\Program Files\ SourceGear\Common\DiffMerge\;C:\Program Files\Microsoft Windows Performance Tool kit\;C:\Program Files (x86)\Common Files\Plantronics\;C:\Program Files (x86)\Pla ntronics\MyHeadsetUpdater\;C:\Program Files (x86)\Plantronics\VoyagerEdge\;C:\Pr ogram Files\IBM\RationalPurifyPlus;C:\Ruby21\bin;%APPDATA%\Python\Scripts
Using an indirect conversion as you suggest would not be convenient, thus I've avoided it, but may be my only option. I implemented the following:
{ QString temp("blah"); QByteArray arr = temp.toUtf8(); std::string temp_str(arr.data()); qDebug() << temp; qDebug() << arr; qDebug() << temp_str.c_str(); }
The program did not crash and the output:
"blah" "blah" blah
I could try the minGW version, but I have concerns. Our Visual Studio projects are generated using CMake. The CMake scripts generate our project files for Windows, Linux/Unix and MacOS. I am fairly certain it can handle an output compatible with MinGW, but may introduce difficulties if changes need to be made, as the ripples could cause us to rework the scripts to maintain the ability to generate project files for the other platforms. Again, I may have no other option, so I won't discount it.
Another thing I have not considered, we use the Adaptive Communications Environment (ACE) which is a public-domain, platform-independent middleware that abstracts our threading, networking and many other tasks. This requires that our executables have ACE_main as its entry point. Since its only an entry point to the main execution thread, I doubt it's implicated, but I do plan on trying a sample app without it to remove this variable to be certain. Nothing is making sense, so it's worth a shot. Without a fix for this problem our project is dead in the water with a deadline looming.
-
@DRoscoe said:
In this case, the copy from
temp_str
totemp_str2
caused the crash. The output from what did execute:QString: "blah" TEMP_STR: blah2
There's no doubt then that the std::string is being constructed with invalid data (possibly with an invalid char* pointer).
Here is the contents of my PATH variable:
I was looking for common crash culprits in Qt-based projects, but didn't find any in your PATH. I don't recognize a number of the tools you're using though.
Using an indirect conversion as you suggest would not be convenient, thus I've avoided it, but may be my only option.
...
The program did not crash and the output:"blah" "blah" blah
Ok, we now have one workaround, at least.
The implementation of QString::toStdString() is pretty straightforward:
- http://code.woboq.org/qt5/qtbase/src/corelib/tools/qstring.h.html#_ZNK7QString11toStdStringEv
- http://code.woboq.org/qt5/qtbase/src/corelib/tools/qbytearray.h.html#_ZNK10QByteArray11toStdStringEv
Maybe try
temp.toUtf8().toStdString()
and see if that avoids the crash. If so, perhaps you can do a find-and-replace.I could try the minGW version, but I have concerns.
Agreed; that is a drastic change. I would use the multi-step conversion, personally.
Another thing I have not considered, we use the Adaptive Communications Environment (ACE).... I do plan on trying a sample app without it to remove this variable to be certain.
Yes, do test it.
-
I tested the shorthand conversion you suggested with the same result. I have also confirmed that the ACE_main entry is not causing a problem. What I have done is implement a static function to do the conversion you gave me, that I've already confirmed works. I hate not having a proper solution for this, but at least I can move forward.
I'm not going to mark this one as solved, as it technically is not. I am planning on trying this on MSVC 2013 to see if it makes a difference.
Thanks!