Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

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 my ChartWidget. Within the paintEvent there is a call to a COM object which paints onto a HDC which ultimately becomes a GDI bitmap, which I then paint onto my QWidget. 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);
    }
    

  • Qt Champions 2017

    You don't check any of the handles for being valid or not ...



  • @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 the prev 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 :)



  • @kshegunov You are absolutely correct - error checking has been added. Testing now so will see if the outcome is different.



  • 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 the QObjectPrivateData 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 from QObject 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!!!


Log in to reply