Skip to content

Hints for static globals

Monday, 16 July 2007  |  jaroslaw staniek

First, did I say thank you to Kenny Duffus in this blog? Then Big Thanks Kenny, and the Akademy 2k7 Team!

There were hacking days @ Akademy but also at least two hacking midnights; the latter (after moving out from Glasgow's Free House pub) was used by me and Holger Schröder to realize what can be wrong at run time in case of larger KDE apps.

[image:2887 width=500]

Finally we are able to run Kexi 2.0 (alpha) on Windows as easily as on Linux: [image:2888 width=500]

What is the problem? When you start porting you application or library to Windows (with gcc, msvc, ...) you can get a runtime error like "The application failed to initialize properly (0xc0000005)". Expect this before entering into main().

The reason for such oddity is that on Windows constructors are not executed for global static data placed in dlls. Yeah, I've heard one gently "uuuuuuu" during the Akademy's lightning talks when mentioned that ;)

So if you have anything like

FooClass foo;

in your .cpp file of your library, and FooClass is nontrivial and have method(s) that crash e.g. because of uninitialized pointers, you won't be able to even enter to a breakpoint set within main() to locate the problem.

Solution how to avoid this bug: use K_GLOBAL_STATIC macro for delayed instantiation on the heap. It's also good for efficiency, and as such it has been already advertised on Linux/Unix platforms.

Solution how to fix the problem if you found it in your just-compiled-on-windows app? You obviously need to find any places with such globals. You can analyze library's object dump or perhaps you just remember all such places in your code. Anyway, I did not find a sane and worth to implement Krazy check for this kind of dangerous code.

If you're looking for a brainless way for performing detection - just check it on runtime. Let's focus on case when global member is QObject-derived. Use gdb on Linux/Unix to set pending breakpoint for setParent():

gdb yourapp b QObject::setParent(QObject*) b main r

setParent() is called from every QObject constructor and apparently the breakpoint at setParent() worked better for me than setting breakpoints directly within constructors. Note again: this has to be executed on Linux/Unix. On windows gdb cannot set breakoints this way (i.e. before entering into main).

You can set breakpoint on any other method that you know will be called during static initialization of the library on Linux/Unix.

Now the only thing you have to do is to 1) note down all the occurences when execution broke at setParent() and before main(); 2) replace their direct instantiation with K_GLOBAL_STATIC or K_GLOBAL_STATIC_WITH_ARGS.

K_GLOBAL_STATIC(FooClass, foo)

There was at least one app in KDEEDU with this problem. Good to see some more applications running.