Unsolved Memory access errors from QMessageBox
-
I am using Qt 5.5 on Windows 8.1. As a result of an application crashing when a dialog box is displayed, I ran it under DrMemory, and discovered that there are memory access errors when I launch any kind of dialog box. The problem is reproducible from the following very simple QMessageBox code:
#include <QApplication>
#include <QMessageBox>int main(int argc, char* argv[])
{
QApplication app(argc, argv); // application object manages everythingQMessageBox* messageBox = new QMessageBox;
messageBox->setWindowTitle("My Message");
messageBox->setText("Hello World");
messageBox->setModal(true);
messageBox->exec();
delete messageBox;
}To be precise, the access errors happen when the mouse is hovered over the "ok" button and then moved away. Launching a QPushButton on its own instead of a QMessageBox also causes the errors. Parenting the message box to a QMainWindow does not help. The DrMemory reports look like this (though there are usually several such errors):
Dr. Memory version 1.9.0 build 0 built on Aug 28 2015 22:56:18
Dr. Memory results for pid 8724: "MessageBox.exe"
Application cmdline: ""C:\Users\Nigel\Visual Studio Projects\Qt.build\bin\Debug\MessageBox.exe""
Recorded 110 suppression(s) from default C:\Program Files (x86)\Dr. Memory\bin\suppress-default.txtError #1: UNADDRESSABLE ACCESS beyond heap bounds: reading 0x0365f8b0-0x0365f8b8 8 byte(s) within 0x0365f8b0-0x0365f8c0
#0 Qt5Guid.dll!QPainter::drawImage +0x1a928 (0x00e7b0d8 <Qt5Guid.dll+0x4b0d8>)
#1 Qt5Guid.dll!QPainter::drawImage +0x317822 (0x01177fd3 <Qt5Guid.dll+0x347fd3>)
#2 Qt5Guid.dll!QPainter::drawImage +0x3119a8 (0x01172159 <Qt5Guid.dll+0x342159>)
#3 Qt5Guid.dll!QPainter::drawImage +0x32d55d (0x0118dd0e <Qt5Guid.dll+0x35dd0e>)
#4 Qt5Guid.dll!QPainter::drawImage +0x1df01 (0x00e7e6b2 <Qt5Guid.dll+0x4e6b2>)
#5 Qt5Widgetsd.dll!QAbstractScrollArea::setHorizontalScrollBar+0x13d6b5 (0x6502f096 <Qt5Widgetsd.dll+0x15f096>)
#6 Qt5Widgetsd.dll!QAbstractScrollArea::setHorizontalScrollBar+0x13626d (0x65027c4e <Qt5Widgetsd.dll+0x157c4e>)
#7 Qt5Widgetsd.dll!QAbstractScrollArea::setHorizontalScrollBar+0xccf27 (0x64fbe908 <Qt5Widgetsd.dll+0xee908>)
#8 Qt5Widgetsd.dll!QAbstractScrollArea::setHorizontalScrollBar+0x15f8c7 (0x650512a8 <Qt5Widgetsd.dll+0x1812a8>)
#9 Qt5Widgetsd.dll!QAbstractScrollArea::setHorizontalScrollBar+0x1482d2 (0x65039cb3 <Qt5Widgetsd.dll+0x169cb3>)
#10 Qt5Widgetsd.dll!QAbstractScrollArea::setHorizontalScrollBar+0x139aaf (0x6502b490 <Qt5Widgetsd.dll+0x15b490>)
#11 Qt5Widgetsd.dll!QAbstractScrollArea::setHorizontalScrollBar+0x1a4b5c (0x6509653d <Qt5Widgetsd.dll+0x1c653d>)
#12 Qt5Widgetsd.dll!QAbstractScrollArea::setHorizontalScrollBar+0x244a66 (0x65136447 <Qt5Widgetsd.dll+0x266447>)
#13 Qt5Widgetsd.dll!QAbstractScrollArea::setHorizontalScrollBar+0x7e6eb (0x64f700cc <Qt5Widgetsd.dll+0xa00cc>)
#14 Qt5Widgetsd.dll!QAbstractScrollArea::setHorizontalScrollBar+0x183470 (0x65074e51 <Qt5Widgetsd.dll+0x1a4e51>)
#15 Qt5Widgetsd.dll!QAbstractScrollArea::setHorizontalScrollBar+0x244a1a (0x651363fb <Qt5Widgetsd.dll+0x2663fb>)
#16 Qt5Widgetsd.dll!QAbstractScrollArea::setHorizontalScrollBar+0x33aad (0x64f2548e <Qt5Widgetsd.dll+0x5548e>)
#17 Qt5Widgetsd.dll!QAbstractScrollArea::setHorizontalScrollBar+0x31c14 (0x64f235f5 <Qt5Widgetsd.dll+0x535f5>)
#18 Qt5Cored.dll!QSortFilterProxyModel::mapToSource +0x2ca891 (0x66a26b47 <Qt5Cored.dll+0x2e6b47>)
#19 Qt5Cored.dll!QSortFilterProxyModel::mapToSource +0x3e9a42 (0x66b45cf8 <Qt5Cored.dll+0x405cf8>)
Note: @0:00:23.901 in thread 7476
Note: next higher malloc: 0x0365f8b8-0x036613ac
Note: 0x0365f8b0-0x0365f8b8 is 28 byte(s) beyond memory 0x0365dda0-0x0365f894 that was freed here:
Note: # 0 replace_free [d:\drmemory_package\common\alloc_replace.c:2514]
Note: # 1 Qt5Guid.dll!QPainter::drawImage +0xe28d9 (0x00f4308a <Qt5Guid.dll+0x11308a>)
Note: # 2 Qt5Guid.dll!QPainter::drawImage +0xea41e (0x00f4abcf <Qt5Guid.dll+0x11abcf>)
Note: # 3 Qt5Guid.dll!QPainter::drawImage +0xdb28b (0x00f3ba3c <Qt5Guid.dll+0x10ba3c>)
Note: # 4 Qt5Widgetsd.dll!QAbstractScrollArea::setHorizontalScrollBar+0xc0e56 (0x64fb2837 <Qt5Widgetsd.dll+0xe2837>)
Note: # 5 Qt5Cored.dll!QSortFilterProxyModel::mapToSource +0x2d4ed (0x667897a3 <Qt5Cored.dll+0x497a3>)
Note: instruction: movdqa (%ecx,%eax,4) -> %xmm0===========================================================================
FINAL SUMMARY:DUPLICATE ERROR COUNTS:
SUPPRESSIONS USED:
ERRORS FOUND:
1 unique, 1 total unaddressable access(es)
0 unique, 0 total uninitialized access(es)
0 unique, 0 total invalid heap argument(s)
0 unique, 0 total GDI usage error(s)
0 unique, 0 total handle leak(s)
0 unique, 0 total warning(s)
0 unique, 0 total, 0 byte(s) of leak(s)
0 unique, 0 total, 0 byte(s) of possible leak(s)
ERRORS IGNORED:
61 potential error(s) (suspected false positives)
(details: C:\Users\Nigel\AppData\Roaming\Dr. Memory\DrMemory-MessageBox.exe.8724.000\potential_errors.txt)
199 potential leak(s) (suspected false positives)
(details: C:\Users\Nigel\AppData\Roaming\Dr. Memory\DrMemory-MessageBox.exe.8724.000\potential_errors.txt)
5 unique, 10 total, 3234 byte(s) of still-reachable allocation(s)
(re-run with "-show_reachable" for details)
Details: C:\Users\Nigel\AppData\Roaming\Dr. Memory\DrMemory-MessageBox.exe.8724.000\results.txtIs there something wrong with my program, perhaps something wrong with my installation, or is it a bug in Qt?
-
Try change QMessageBox* messageBox = new QMessageBox;
to
QMessageBox messageBox;
and remove delete messageBox; -
first of all you should start the main event-loop (QApplication::exec())
And open the the messageboxes once it runs, then check again if the error occurs. -
@Helson Thank you for your reply. Unfortuntately changing QMessageBox to an automatic variable makes no difference.
-
@raven-worx
thank you for your reply. I did forget to add app.exec() at the end, but adding it does not remove the errors.It's a bit tricky in this small example to run app.exec() before showing the box. However, in my much larger application, the dialogs and message boxes are created by events from a QMainWindow, when the QApplication is already running, and they do suffer from the same problem. Curiously the main window is itself completely clean of errors.
-
@NigelMcFarlane
the callstacks you've posted don't make much sense and i would say they can be carelessly discarded.
So maybe you are overwriting the some memory in your application .. i don't know.
And obviously you haven't even tried the snipped you've posted but claim that it isn't working. You should run this minimal example and check again if it still crashes. This is as easy as subclassing a plain QWidget and open the dialog on a button press for example.
If it doesn't crash the issue is somewhere else in your code. -
@raven-worx
I may not have attempted your suggestion on the mini-snippet but I most certainly tested the snippet itself before I posted it!!
In any case, I have now found the cause of the crash in my application, and it was not caused by these "leaks". Whatever they are, they seem to be harmless. If no one else is seeing them perhaps they are just artefacts of the diagnostic tool. -
Normal practice is to construct with an argument
QMessageBox* messageBox = new QMessageBox(this);
and let Qt automatically delete it when "this" goes out of scope. This follows the RAII principle.
-
Hello,
Are you sure that this stack trace corresponds to the particular example code?
These two lines:#18 Qt5Cored.dll!QSortFilterProxyModel::mapToSource +0x2ca891 (0x66a26b47 <Qt5Cored.dll+0x2e6b47>) #19 Qt5Cored.dll!QSortFilterProxyModel::mapToSource +0x3e9a42 (0x66b45cf8 <Qt5Cored.dll+0x405cf8>)
are most certainly very suspicious. I wouldn't expect a message box to have anything to do with any of the model classes. That said, I don't believe you can have a modal dialog as a main window, it makes no sense - it should be modal to what? Maybe simply try showing it as you would any other ordinary widget, i.e:
int main(int argc, char ** argv) { QApplication app(argc, argv); // application object manages everything QMessageBox messageBox; messageBox.setWindowTitle("My Message"); messageBox.setText("Hello World"); messageBox.show(); return QApplication::exec(); }
Kind regards.
-
@mjsurette
Thank you for your reply, I did not know that Qt objects were smart pointers in this way.
Regards
Nigel -
@kshegunov
Thank you for reply.
I don't think the error list actually represents a stack trace in any way, though I agree that the list of classes involved is strange.Now I know these "errors" were a red herring in terms of my larger application crashing; they seem to be harmless, possibly an artefact of Dr Memory or my Windows installation, and I guess not of great general interest. If I get a moment I might try running a different memory tool for comparison.
Thank you
Best regards
Nigel -
@NigelMcFarlane
Hello,Thank you for your reply, I did not know that Qt objects were smart pointers in this way.
QObject
s are smart in many ways, they can and will make your life easier in multitude of cases, but one should know when and how to use them cleverly. I will argue what @mjsurette suggested, namely this:Normal practice is to construct with an argument
QMessageBox* messageBox = new QMessageBox(this);
and let Qt automatically delete it when "this" goes out of scope. This follows the RAII principle.to be a bad advice! It is true that your
QWidget
(this
is supposed to be aQWidget
in this case) will free the message box in its destructor, however you're delegating responsibility for a local variable to the global scope (not program-global, but class-global). What happens to the message box when you give it a parent is that it's added to the list of children of your widget. Putting aside the visual implications (as children are shown only inside their parent widget) you're creating an (almost) dangling object - you lose the ability to manipulate and/or delete it as soon as your function goes out of scope. In many cases this isn't a problem for objects that are in actuality expected to persist in memory (i.e. creating a layout for a widget), because naturally the widget takes ownership of the layout and uses it to display itself, unfortunately this is not the case here. Suppose you have that code in a function and that function is called a 100 times, this code leads to 100QMessageBox
objects just waiting in the children list to be deleted some day when the parent has been destroyed. Since mostQWidget
instances persist through the whole lifetime of your application this simply means that the memory is freed when your application exits. Remember neither Qt nor C++ is Java! Another point is that aQObject
is already dragging along a heap allocation for its private object (the PIMPL idiom is used throughout Qt), so there is not really a good reason to use heap allocations for local variables, the stack is faster, more robust and less error-prone. The RAII comment is just plainly wrong, since any local stack variable does not break RAII by design. When the stack is unwinding the local object's destructor will be called and memory freed, it doesn't matter whether the reason was an exception being thrown or the function going out of scope. Since message boxes are mostly modal the best way is to use:QMessageBox messageBox; messageBox.setText("Some text"); // ... More initialization messageBox.exec(); //< This waits for the user input and returns when the message box is closed. // .. Handle here the return value of `QMessageBox::exec`
Another option is to use one of the pre-made static functions available for the
QMessageBox
class, which would be my preferred choice. However, as I said in my previous comment, this is a bit different when you use the message box as a top-level window (no parent, defined in main), because you don't have theQApplication
's event loop running when show()/exec() is called.Back to the original issue
The lines I cited do look like a stack trace and don't correspond to the actual code provided, hence @raven-worx's frustration that I share. If I had to guess what the problem is, my suggestion is to check your memory allocation/freeing, as this heap problems occur often on double delete or dereferencing dangling pointer, but no one can say for sure without a code to check against, or at least look upon. If your application is crashing, rely on the debugger to provide the relevant information - where and why this occurred, and not memory inspection tools, they will not give you the answer. If you're instead tracing a (possible) memory leak, then you could try them.
PS. This got a bit lengthy, but I hope is helpful.
Kind regards.
-
@kshegunov
Hello,
The report is definitely from the small QMessageBox program. If it's impossible that Qt could be calling these routines from this program, it suggests that the output of Dr Memory is not reliable, at least on my installation.I set the program to run under VLD and this reported no leaks, which also suggests a problem with Dr Memory.
Regarding the "smart pointers" issue: if I do not delete the QMessageBox, vld reports it as a memory leak.
Best regards
Nigel