Qt and Exception Trapping
-
I've been battling with an exception issue which occurs about 20/25/30 minutes into my application running on Windows 10. Try as I might, I am not able to find the location of the crash nor figure out what is triggering it.
The application runs perfectly then all of a sudden, terminates with the following information taken from Event Viewer:
EventData: MyApp.exe 1.0.0.1 5b686e4f ucrtbase.dll 10.0.17134.191 cb91c047 c0000409 000a253b 2fec 01d4355f109eee82
Is there any way, within the scope of Qt, whereby I can trap unhandled exceptions and gleam some meaningful information from them. I appreciate that Qt doesn't really support exceptions but is there any static routine which I can implement/override which could tell me the faulting module, line, column, etc?
-
@webzoid
(So far as I know) your best chance is to run it in a debugger, sometimes you get a useful traceback (though often not as it's buried away in Windows libraries). You won't see line numbers etc. unless you've compiled for debug. If you compile Qt yourself, compile that for debug too.Google for
ucrtbase
. Some suggestion it's an MSVC module.You have a 1 in 1,000 chance that if you Google for some of those memory address numbers you'll find someone else with similar problem....
-
Unfortunately debugging doesn't help, I can't recreate the exact issue on my development machine. The issue is with the program running on a customers machine. I've pretty much exhausted all the Google links to
ucrtbase
and all the error codes that go with it - lots are game-related, some are Microsoft Word related, others are meaningless.Following my initial post, I've implemented a
MiniDump
class from the following link:http://blog.aaronballman.com/2011/05/generating-a-minidump/
Setting it up as follows in
main
:LONG WINAPI MyCrashHandler(EXCEPTION_POINTERS * /*ExceptionInfo*/) { MiniDump dump; dump.Create(L"AppCrash.dmp"); return EXCEPTION_EXECUTE_HANDLER; } int main(int argc, char *argv[]) { QApplication a(argc, argv); // Other init code removed... ::SetUnhandledExceptionFilter(MyCrashHandler); // Create a MainWindow and show it maximized MainWindow w; w.showMaximized(); return a.exec(); }
The resulting
dmp
file when opened in Microsoft Visual Studio gives me the following call stack:ntdll.dll!77eaa22c() [Frames below may be incorrect and/or missing, no symbols loaded for ntdll.dll] [External Code] Qt5Gui.dll!QPalette::QPalette() Line 536 MyApp.exe!_com_issue_errorex(HRESULT hr, IUnknown * punk, const _GUID & riid) Line 66 MyApp.exe!S57Draw::paint(QPainter * painter, QRect rect) Line 115 MyApp.exe!ChartWidget::paintEvent(QPaintEvent *event) Line 384 // etc
So, what I can gleam from the above info is that the actual exception is occurring in the
paintEvent
function of myChartWidget
. Within thepaintEvent
there is a call to a COM object which paints onto aHDC
which ultimately becomes a GDI bitmap, which I then paint onto myQWidget
. It also looks like there is something COM-related which is causing issues... -
@webzoid said in Qt and Exception Trapping:
MyApp.exe!S57Draw::paint(QPainter * painter, QRect rect) Line 115
Probably won't help further but.... That seems to be from https://encx.com/reference/interface_i_s57_draw.html#a6c50588412be1774e10cc0758a05fa83
Do you have the sources? Does line #115 convey anything helpful?
-
@JonB Yeah, that's my thinking with regards to the source of the exception.
The line in question,
115
(I've highlighted this by way of a comment) refers to this block of code from within my application:void S57Draw::paint(QPainter *painter, QRect rect) { // Width and height of our paint area int width = rect.width(); int height = rect.height(); // Get the CSS background color QColor bg = painter->background().color(); COLORREF color = RGB(bg.red(), bg.green(), bg.blue()); HDC hDC = CreateCompatibleDC(NULL); DWORD *srcData = nullptr; BITMAPINFO bmi = { sizeof(BITMAPINFOHEADER), width, // Negative height means that the image is drawn vertically flipped // which is what we want. Normal height draws the image flipped, for some reason -height, 1, 32, BI_RGB, 0, 0, 0, 0, 0 }; HBITMAP bmp = CreateDIBSection(hDC, &bmi, DIB_RGB_COLORS, (void **)&srcData, 0, 0); HGDIOBJ prev = SelectObject(hDC, bmp); // Fill the background HBRUSH br = CreateSolidBrush(color); RECT r = { 0, 0, width, height }; FillRect(hDC, &r, br); // Draw the S57 chart onto our memory dc m_ptr->Draw(reinterpret_cast<OLE_HANDLE>(hDC)); // ##### WHAT FOLLOWS IS LINE 115 ##### SelectObject(hDC, prev); GdiFlush(); { // Scoped so that the QImage is destroyed before HBITMAP QImage img((uchar *)srcData, width, height, QImage::Format_RGB32); painter->drawImage(0, 0, img); } DeleteObject(br); DeleteObject(bmp); DeleteDC(hDC); }
-
@webzoid said in Qt and Exception Trapping:
You're way beyond my pay grade here (and I actually though that
S57Draw
was in some library....) I'm afraid. Is theprev
you're reselecting which you got earlier on invalid now? But that's it for my input, you need someone else who knows what they're talking about :) -
Ok, so an update...
The code sample I posted was fine, there were no issues caused by the lack of error-checking (although bad practice, I admit).
Fundamentally, the issue was related to difficult to trace memory leaks. As QtCreator for Windows does not have any native memory profiling or debugging tools, I decided to get Visual Studio to attach to my application. I didn't realise but VS has some nice memory snapshot tools which allowed me to keep track of the heap and ultimately solve the problem.
I had a rogue class which inherited from
QObject
and it was the underlying implementation of theQObjectPrivateData
which was adding an extra 1.5MB to the heap on every new class instance. I decided that actually, I didn't need to derive fromQObject
and therefore the issue has now been resolved.So, if there's a useful tip for those who are having memory issues - use Visual Studio for debugging. It's brilliant!!!