Original URL: http://www.theregister.co.uk/2007/10/11/binary_interfaces_2/

Binary interfaces in component development

A template class with static data - how can that possibly go wrong?

By Dan Clarke

Posted in Software, 11th October 2007 08:02 GMT

Part 2 In the first part of this series we looked at how problems emerge when we make the transformation from source code to binary code, and we saw that even when the code is correct errors can be introduced by using dynamic libraries instead of a monolithic binary.

With some simple examples, we’re starting to see problems, using a logically correct C++ program for which we cannot construct a physical representation using dynamic libraries because of platform constraints.

In software security, the industry experts speak of security exposures that occur in the interactions between systems. I think we’re now seeing a similar issue with the interaction of the abstract C++ system and the physical portable executable format system; but instead of a security problem, we get bugs.

Our example comes from real life code, and a large development team that has lived with consequent problems in its Windows environment for a long time, which have cost a lot of money. The issue comes from the interaction of two C++ language features that behave unexpectedly when combined with dynamic linking. We’ll see how on Windows that code packaged in dynamic libraries doesn’t behave in accordance with the C++ language, and we’ll see how to use tools to investigate and resolve the problem. The code we’ll use to expose this insidious problem is shown in the following generic implementation of the Singleton pattern. As we’ll see, this code works fine provided it is not used with dynamic libraries:

// GenericSingleton.hpp
template <typename T>
class GenericSingleton
{
public:
   T &getInstance();

private:
   static T m_instance;
};

template <typename T>
T & GenericSingleton<T>::getInstance()
{
    return m_instance;
}

template <typename T>
T GenericSingleton<T>::m_instance; 

There’s a template class with all of its definitions in the header file. This organisation of a class template is common, perhaps because placing the template definitions in the header file avoids lots of annoying linker warnings. However, as we’ll see, this practice leads to problems once the transition is made from a small monolithic binary program to a modular software system composed of interacting dynamic libraries.

Firstly, why is this code problematic in conjunction with dynamic libraries? There are issues here on Windows and on Linux, but the manifestations of the problems are different.

As we know, with few exceptions, a C++ compiler instantiates a template whenever it is specialised, and the template definitions are available (see the ISO C++ standard paragraph 14.7.1). In our code, the template definitions are in the header file so the template definitions are always available. This means that each cpp file that uses the template will contain instantiated definitions of the static object in the compiled object file. When object files are linked, the linker notices that there are many definitions of a single symbol and it merges all definitions into a single definition. Such symbols are marked in the object file as “weak”, so that the linker will unify multiple definitions instead of complaining about a multiply-defined symbol. A counter example of a “strong” symbol is a non-inline function definition; here the linker would give an error if it came across a duplicate definition.

When these definitions all occur in a single monolithic binary, there are no problems. This is shown by the following example, where we introduce a singleton class that we implement via our GenericSingleton template. If the implementation works correctly then this object will be constructed and destructed only once. To test our singleton we add two further cpp files containing code that uses the resulting singleton, and a further cpp containing the main function. In our initial test, we run it as a monolithic binary and we expect that only a single singleton object will be constructed – see Figure 1.

Figure 1: Shows that everything is OK when we're building statically.

The above is the case where our binary is linked monolithically, using only static libraries and everything works. Now, imagine a scenario where your manager wants to decompose the project, so that different project teams can be responsible for their own dynamic library, so that development can occur in parallel, so that functionalities can be unit tested without rebuilding everything - and for all the other reasons that motivate people to use dynamic libraries. This manager, like lots of people, comes from a planet where an application can be built interchangeably, either statically or dynamically, with no difference in behaviour.

I’m sure we’d all like to come from this programmer’s paradise too, but until we can find a way to move there, maybe we’ll have to support our user base here on Earth with its less than perfect operating systems. So, what will happen when we take our simple program and change it from a monolithic binary into a set of dynamically-linked components?

In the next example (see Figure 2) the code is logically and textually identical apart from the usual dllimport and dllexport specifiers. Later in this article we’ll see more about these and how they work, but for this example they’re not important. Instead, we want to focus on the behaviour change; our singleton is no longer living up to its name. Two singleton objects are created and the Gang of Four are already drafting a blog entry, complaining about our corruption of their pattern.

Figure 2 – Shows the dynamic version, where our Singleton is constructed twice.

So what has happened here? Earlier we noted that a C++ compiler would (with few exceptions) instantiate a class template and its member functions when it’s specialised and the template definitions for the member functions are available. The Windows behaviour is that both A and B are dlls, making calls to member functions in our singleton class. The template definitions are in the header file and hence always available (they are always instantiated). As a result, both A.dll and B.dll contain a definition for our static variable. However, if we try to confirm this by using the dumpbin command that comes with Visual Studio, there’s no trace of our static variable anywhere in the dynamic libraries (see Figure 3). In the linker map output (see Figure 4), we can see that the symbols are still in the library but the identifying names have been eliminated.

Figure 3: Dumpbin of all dll information 
(N.B. no mention of our static variable!).

D:\ …\code\somemodularexe\Release>dumpbin /all DynLibUsingSingletonA.dll 

SECTION HEADER #1
   .text name
   119ED virtual size
    1000 virtual address (10001000 to 100129EC)
   12000 size of raw data
    1000 file pointer to raw data (00001000 to 00012FFF)
       0 file pointer to relocation table
       0 file pointer to line numbers
       0 number of relocations
       0 number of line numbers
60000020 flags
         Code
         Execute Read

RAW DATA #1
  10001000: C7 01 B4 31 01 10 E9 17 2D 00 00 CC CC CC CC CC  Ç.´1..é.-..ÌÌÌÌÌ
  10001010: 56 8B F1 C7 06 B4 31 01 10 E8 04 2D 00 00 F6 44  V.ñÇ.´1..è.-..öD
  10001020: 24 08 01 74 09 56 E8 D9 2D 00 00 83 C4 04 8B C6  $..t.VèÙ-...Ä..Æ
  10001030: 5E C2 04 00 CC CC CC CC CC CC CC CC CC CC CC CC  ^Â..ÌÌÌÌÌÌÌÌÌÌÌÌ
  10001040: 8B 44 24 10 8B 4C 24 0C 8B 54 24 08 56 8B 74 24  .D$..L$..T$.V.t$
                                …       ….      …

Figure 4: Linker map output showing variable definition.

0004:00001b60 ?myNsExportedVar@A@@3HA    100b2b60     A.obj
0004:00001b64 ?m_instance@?$GenericSingleton@VMySingletonObject@@@@0VMySingletonObject@@A

The reason we can’t see the static objects in the dumpbin report is that in our example we haven’t tagged the instantiated objects of static duration as dllexport. As a result, in Microsoft’s portable executable format, the linker doesn’t add them to either the export section of the dll - or even preserve the symbol names. After all, if a symbol isn’t exported there’s no need to put its name into the dll; as all references to it are known at link time. However, under such a system we cannot expect our static data at runtime to behave as C++ indicates that they should, with a single instance across the program.

Clearly, the linker has no chance to resolve multiple definitions of a single symbol if the symbol name is not present to connect all the different instances together. As a first step to resolving this problem, we’ll use linkage specifiers to bring our data into the export, to see if that helps solve the problem.

However, in Microsoft Visual Studio there exists a mechanism to tag a definition that will be exported from a dll. This tag causes the linker to put the symbol name of the definition into the dll export table so that other binaries using the dll can find the definition. A second tag allows you to import definitions from a dll, signalling to the linker not to search for the definition at link time but instead to use an indirection which will be replaced at runtime by the real definition, in a process known as 'fixup' (see also here). In code, you typically see a system of macros to manage this tagging. Declarations that form the interface of the dynamic library are marked with this macro and when building on windows the preprocessor substitute the macro for ‘__declspec(dllexport)’ indicating to the linker that the symbol should be placed in the export table for use by other binaries linking to the library. When building a binary that uses a dll, the same macros expand to ‘__declspec(dllimport)’ indicating to the linker that the needed definition will be available at runtime if it’s not found. There’s one problem with this system, however. It works reasonably well when the binary definition is located in the library corresponding to the C++ class definition; but in a world of templates, the template definition could be located in some library far, far away, although its instantiation is in the library that you’re building.

If you have control over the template definition, you may be able to get past this with an increasingly messy system of macros as illustrated in the code below, but if the template definition is from a third party library then the only option is to hide any template instantiations far away from the interfaces of the dynamic library.

So, by adding a rather elaborate system of macros (check the code for this figure if you’re interested), we’re able to get our static data into the exports table. Just to clarify, I’m not recommending the usage of such a system of macros; it’s simply a way to get the static variable resulting from the instantiation of a template from another library exported. Have these efforts solved the problem though? Unfortunately not, as the following screenshot (Figure 5) reveals; depending on which dll the calling code is in. The static variable GenericSingleton<MySingletonObject>::m_instance is located at a different memory address.

Figure 5: Shows one static variable with 2 locations.

In our case, an important difference means this system will not work. Our class template is not defined in our dll so its definition is not tagged with the macro that expands to dllexport. Using a modified mechanism, we were able to export the symbol, but as both dlls needed to instantiate the variable and type, this still didn’t resolve the issue.

What’s the solution? Unfortunately, the solution is to choose a software architecture that doesn’t expose you to this incoherence between dynamic libraries and static data. In the example we’ve seen, the problem comes from how dynamic libraries work on windows, but on Linux, there are equivalent ways to get stung by this issue. [If people are interested leave a comment and we can look at it next time.]

In conclusion, what do we think the specific problems are with this architecture, which then led us into this trap? Firstly, the person who came up with the idea of using a class template to implement the singleton pattern needs to be spoken to severely. Management of static data is always so problematic in C++ that when it is used, the location of its definition must be carefully considered, so that the same definition is used in all places that it is needed. To choose an implementation technique such as templates, that obliges the compiler to put definitions of the same piece of static data in every object file for a pattern that exists to manage static data, is a little thoughtless.

Secondly, there are times when we do really need static data in templates. Not for a Singleton pattern, we’re probably all agreed; but sometimes it can be an extremely powerful implementation tool. In these cases, we should manage the location of the definition carefully, by not exposing the template definitions in the interfaces and instead using explicit instantiation at the appropriate place. The cost of explicit instantiation is that the template can only be used for types that are known to the template definition in advance; but if you don’t do this, you guarantee later problems for yourself, when running with dynamic libraries on Windows.

Finally, you can use the same code with explicit instantiation – it now works but this shouldn’t be regarded as a fix for the implementation, as the cost of having to know all Singleton types in advance is a big problem for this class. And a further note: for all the trouble caused by the template implementation, could we not just have written a non-template version, and duplicated the two lines of code whenever we needed to?

Resources:

The Win32 Portable Executable File Format: http://msdn.microsoft.com/msdnmag/issues/02/02/PE/.

The PEBrowse Windows disassembler and static-analysis tool: http://www.smidgeonsoft.prohosting.com/pebrowse-pro-file-viewer.html.

The program linker and what it does: http://www.microsoft.com/msj/0797/hood0797.aspx.

The Sourcecode used for this article, in a zip archive.