#10 closed defect (fixed)
Trap issuing stdlib's exit() when QApplication instance is created on the stack in main()
Reported by: | dmik | Owned by: | dmik |
---|---|---|---|
Priority: | normal | Milestone: | qt-os2-3.3.1-rc07 |
Component: | kernel | Version: | 3.3.1-rc06 |
Severity: | normal | Keywords: | trap exit() |
Cc: |
Description
If we have a QApplication instance created on the stack in main() (a very common practice for 99% of Qt apps), then an attempt to call the exit() function from stdlib will produce an application trap with a popuplog entry (SYS3170/c0010001, most likely in DOSCALL1.DLL).
A simple example to reproduce:
#include <qapplication.h> #include <stdlib.h> int main (int argc, char **argv) { QApplication a (argc, argv); exit (-1); }
From what I've already found, this happens when a global QFontCache (internal QObject subclass) instance is being destroyed (by a static func from the exit list). It is created as a child of QApplication, so its QObject desctructor calls parentObject->removeChild (this);
but for some reason the vtable of the QApplocation instance is already corrupted by that time (but no QApplocation destructor has been called yet!).
Attachments (1)
Change History (6)
comment:1 by , 19 years ago
Status: | new → assigned |
---|
comment:2 by , 19 years ago
comment:3 by , 19 years ago
As it turned out, the trap happens because destructors of static objects in a DLL (static QSingleCleanupHandler<QFontCache> cleanup_fontcache
in our case, see source:trunk/src/kernel/qfont.cpp) are called by DosExit
that seems to reuse the stack of the main thread by the time it calls _DLL_InitTerm
(where destructors are actually called from by libc).
In our case, QFontCache
is a child of QApplication
, and both are subclasses of QObject
. Therefore, when destructed, QFontCache
tries to remove itself from the parent's child list by calling its removeChild
method (see QObject::~QObject
), but the parent located on the stack in main()
is already overwritten.
This is not a GCC or LIBC problem. As I was told by Bird, the behavior of GCC related to the destruction of static objects has been done after IBM Visual Age C/C++. And indeed, VAC 3.08 behaves exactly the same as GCC and produces the same trap -- you can try a simple testcase (that doesn't use Qt at all) attached above.
There are few possible workarounds:
- Don't allocate global objects used by destructors of static objects defined in a DLL on the stack. In case of Qt, it's enough to define a
QApplication
instance outsidemain()
.
- Don't use global objects that can be allocated on the stack from destructors of static objects defined in a DLL.
- Supply your own
_DLL_InitTerm
implementation where you will not call _ctordtorTerm() upon DLL termination, but instead call it from a function registered in the libc exit list (usingatexit()
when the DLL is being initialized). This will, however, not help if the application is being terminated using_Exit()
,DosExit()
,DosKillProcess()
or in other words, by any means other than libc'sexit()
.
For Qt, I will choose the workaround N2 because there is only a single place so far where a stack-based QApplication instance can be called from the static destructor, and because it will also allow to kill Qt applications w/o producing a guaranteed trap.
comment:4 by , 19 years ago
Resolution: | → fixed |
---|---|
Status: | assigned → closed |
QFontCache is now cleaned up from a static atexit()
exit handler (changeset:80). No traps any more, but there is one drawback (not consireded to be significant though): the cleanup will only occur on a normal program termination (i.e. a usual return from main()
), or when exit()
is called. Doing DosExit()
or DosKillProcess()
will leave the object not deleted since stdlib's exit list are not processed in these cases.
Btw, the same trap occurs if we just
DosKillProcess()
any Qt application. Obviously, for the same reason -- unusual order of object destruction.