Fundamentals 7 min read

Why Linking Order Crashes Your C++ Service: The Static Initialization Order Fiasco

A C++ service that crashes after a harmless log module addition is traced back to undefined cross‑file global initialization order, revealing the static initialization order fiasco and how linking order and compiler‑generated init arrays can cause runtime failures.

IT Services Circle
IT Services Circle
IT Services Circle
Why Linking Order Crashes Your C++ Service: The Static Initialization Order Fiasco

Problem description

An operations engineer reports that a stable database service crashes immediately after deployment, even though the new version only adds a trivial logging module. The crash occurs before main is entered, with the debugger pointing to the Database constructor.

Root cause: static initialization order fiasco

In C++, objects with static storage duration (global variables, static members, and function‑local statics) are constructed before main. When such objects are defined in different translation units, the C++ standard does not define the order of their initialization, so the program may access an uninitialized object.

Illustrative code

class Logger {
public:
    void log(const std::string& msg) { /* write log */ }
};

Logger globalLogger; // global logger object
extern Logger globalLogger;

class Database {
public:
    Database() {
        globalLogger.log("Database initializing...");
        // ... database init logic
    }
};

Database globalDB; // global database object

Linking order effect

Compiling and linking with different object file orders shows the issue:

g++ main.o database.o logger.o -o app   # crashes

g++ main.o logger.o database.o -o app   # runs correctly

The program’s behavior changes solely because the linker merges the .init_array sections of each object file in an unspecified order.

Types of static‑storage variables

Global variables – initialized at program start, live for the whole execution.

Static member variables – also initialized at program start and shared by all class instances.

Local static variables – initialized the first time control reaches their definition.

How the linker builds the init array

For each translation unit the compiler generates a function that constructs its static objects, e.g.:

void __GLOBAL__sub_I_logger.cpp() {
    new(&globalLogger) Logger();
}

static void register_init() __attribute__((constructor));

The linker places pointers to these functions into the executable’s .init_array. The order of the pointers is undefined, which leads to the observed crash.

Solution: Meyers Singleton

Wrap each global object in a function that returns a reference to a function‑local static. The static is guaranteed to be constructed on first use, and C++11 makes this initialization thread‑safe.

// logger.cpp
Logger& getLogger() {
    static Logger instance; // constructed on first call
    return instance;
}

// database.cpp
Database& getDatabase() {
    static Database instance;
    return instance;
}

Database::Database() {
    getLogger().log("DB Init"); // safe: logger is initialized before use
}

Takeaway

Never rely on the initialization order of globals spread across multiple source files. Use function‑local statics, dependency injection, or explicit initialization sequences to avoid the static initialization order fiasco.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

C++global variablesLinkerMeyers SingletonInitialization FiascoStatic Initialization Order
IT Services Circle
Written by

IT Services Circle

Delivering cutting-edge internet insights and practical learning resources. We're a passionate and principled IT media platform.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.