std::string destructor crashing in Release when using ::toStdString methods
-
I'm developing an app using QT 5 on Windows. What I am seeing is MSVC10 in RELEASE mode causing std::string to throw an exception. The application then crashes, hitting a breakpoint in the destructor's call to _tidy(). The call stack is useless in this case, as there is a stack/heap corruption. I turned on /DEBUG symbols for the project and walked the code from the debugger. Here is the distilled version of the code I am running:
Foo::doSomething(const QString& temp)
{
std::string temp_str = temp.toStdString();
<do something with temp_str>
}What I am seeing is that the application crashes in the destructor for the std::string object "temp_str" when the method goes out of scope. This only happens in RELEASE mode. In DEBUG mode, everything works fine.
I am using the DLLs that where installed with Qt via the binary installer. I did not compile Qt for my platform as the installer package already contains what I need.
Any ideas what could be going wrong?
-
If it's 100% reproducible and you're sure this isn't a random symptom of some other bug in your code then it might be a case of mixed debug/release dlls. Make sure your app doesn't use debug dllls in release mode by running it through profile mode in Dependency Walker or Process Explorer.
-
I would add to Chris's comment, if this under Window you have to make sure all dependencies use the same C runtime library.
It is a bit more then just release/debug , it also static and dynamic C runtime, multi-/single-threaded version ( last is mostly disappeared from modern compilers, but just in case) . -
Thanks for the replies. I am trying to navigate DependencyWalker results now. I don't see anything obvious so far.
By the way, I misspoke in my original post. It is NOT Qt that is crashing explicitly. It is the destructor for the std::string that is crashing, but only when the std::string in question is generated from QString::toStdString method
-
@DRoscoe said:
std::string temp_str = temp.toStdString();
Can you try what happens with:
std::string temp_str(temp.toStdString());
?
-
That was how the code originally was written, when I first observed the problem. I though perhaps I could solve it by creating a non-temporary copy, but it didn't work.
DependencyWalker did not show me anything obvious. At least I didn't see any reference to debug DLL's. I'm in the process of recompiling the Qt Libraries on my compiler. I am using Visual Studio 2010
-
The example I originally posted is already sufficient to reproduce the problem in my environment, but here is the exact code that is causing the problem:
void CommunicationHandler::decodeMessage(const QByteArray& msg_in) { //DAR@20150416 Because the NAV Database contains a large binary payload, we // need a way to omit this portion of the message for logging if (cur_msg_type == TapMessageClass::NAV_DATABASE) { // The NAV Database is an AOP formatted binary object which begins with the // letters "aop" and a null terminator. QString to_log(msg_in.mid(0, (msg_in.indexOf("aop\0")))); TapMessagingLogger::instance()->logMessage(TapMessagingLogger::RECEIVED, to_log.toStdString()); }
When the call to logMessage goes out of scope, it crashes. If I modify the code as follows:
void CommunicationHandler::decodeMessage(const QByteArray& msg_in) { //DAR@20150416 Because the NAV Database contains a large binary payload, we // need a way to omit this portion of the message for logging if (cur_msg_type == TapMessageClass::NAV_DATABASE) { // The NAV Database is an AOP formatted binary object which begins with the // letters "aop" and a null terminator. QString to_log(msg_in.mid(0, (msg_in.indexOf("aop\0")))); std::string temp_str = to_log.toStdString(); TapMessagingLogger::instance()->logMessage(TapMessagingLogger::RECEIVED, temp_str); }
The crash occurs when the if() clause goes out of scope. It is important to note that this code causes the crash only because its the first time this type of operation is performed. If I prevent it from executing, the problem occurs at a different point using a similar operation.
The bottom line is, in Release mode, whenever a std::string is produced using ::toStdString, the std::string destructor will cause a crash. I added a code snippet like the one in my original post in the constructor of my main application class and it crashed immediately
-
Hi,
if I understood correctly you're trying to log something that is in binary format; IIRC
toStdString()
converts Unicode (QString) into a std::string using utf-8 encoding.Could you try to use directly
QByteArray::toStdString()
instead of passing through a QString? In that case you can avoid encoding step -
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.