Previous section   Next section

Imperfect C++ Practical Solutions for Real-Life Programming
By Matthew Wilson
Table of Contents
Chapter 9.  Dynamic Libraries


9.3. Lifetime

The lifetime problem involves things—code and objects—that can disappear while they are still needed. (See Chapter 31 for the comparable problem of Return Value Lifetime.)

When using implicit loading, this is usually not a problem. The operating system loader keeps all the libraries on which the link unit depends in process memory until the process terminates. Hence, it is rare for the code for a link unit to disappear before it is needed, and the only time I've experienced this was when a dynamic library was implicitly loaded as a result of a dependent library being explicitly loaded. When the latter was unloaded, references to code in the former were left around in the executable, and when they were called, the process bombed. However, this is still explicit loading, just indirectly.

There is another problem, however, with explicit loading, regarding the issue of the lifetimes of C++ objects. Since objects undergo construction prior to coming into existence, and destruction to remove them from existence, if some code references such an object before it's alive, or after it's dead, undefined behavior results. This is the classic static ordering problem, and does not, in and of itself, pertain to dynamic linking; it's just that dynamic linking can exacerbate it. This issue is important enough to deserve its own treatment (see section 11.2) so we'll not discuss it further here.

When using explicit loading, making ghosts of loaded code is remarkably simple to do. If you are using explicit loading to extract symbols from a dynamic library, you must ensure that you do not cache the function address and later use it after you have released the library. The canonical example looks like:



void *lib = dlopen(. . .);


void *pfn = dlsym(lib, ". . .");


dlclose(lib);


((void (*)())pfn)();



Naturally, you'd not get this past your peer-programming partner, never mind the thorough code review your manager had scheduled in the time that the considerate senior V.P. of marketing had granted for the project. However, there are subtle ways in which this can come up. Any time you store a pointer to a function in an explicitly loaded library, you need to ensure that the library will not be unloaded prior to any potential call of that function. This is not as easy as it sounds in the real world, so this issue also gets a bigger coverage in the next chapter when we talk about Thread-Specific Storage.

By the way, I experienced one gotcha several years ago on a UNIX system—it wasn't Linux—that did not do reference counting on its dlopen()/dlclose(). Our program used dynamic libraries within which one or more plug-ins to the application could reside. The program made independent calls to dlopen() for each registered plug-in and, like a good resource-consumer, made the equivalent number of calls to dlclose(). Alas, the first one of these unloaded the library, and subsequent calls to those functions resulted in undefined behavior. Thankfully this kind of thing is reasonably easy to spot, and not too hard to fix. Given that you're probably abstracting the dynamic library loading behind a platform-independent API, this can be catered for, and that's the solution we used.


      Previous section   Next section