Skip to content

Static object initialization order leads to std::string crash #3271

@ljx0305

Description

@ljx0305

Describe the bug
Problem Background
A crash occurred in a C++ project integrating the braft/brpc framework, with the program aborting at std::string::operator= in the standard library's basic_string.h during the static initialization phase. The stack trace showed the crash was triggered in the constructor of brpc::AdaptiveMaxConcurrency, which was instantiated as a global object.
Root Cause Analysis
The core issue stems from the unspecified initialization order of global/static objects across different translation units (.cpp files) in C++. The brpc::AdaptiveMaxConcurrency global object depends on a class static member variable of type std::string for initialization. However, since the initialization order of global objects and class static members across different source files is not defined by the C++ standard, the AdaptiveMaxConcurrency object may be constructed before the dependent std::string static member is fully initialized. This leads to an invalid memory access when assigning an uninitialized string, resulting in a crash in the standard library's string assignment operator.
Solution
To enforce the initialization order (class static member first, global object second) and eliminate the crash, we adopt the Meyers' Singleton pattern (function-local static variables) as the industry-standard solution:
Replace direct class static member definitions with function-local static variables. C++ guarantees that function-local static variables are initialized only when the function is first called, in a thread-safe manner.
Modify the global object's initialization logic to explicitly call the static member's accessor function, ensuring the dependent static member is fully initialized before the global object is constructed.
This approach completely bypasses the unspecified cross-translation-unit initialization order, locks the initialization sequence, and resolves the string assignment crash fundamentally.
Concise Version (for documentation/report)
A crash occurred in a braft/brpc-integrated C++ project during static initialization, triggered by an invalid std::string assignment in brpc::AdaptiveMaxConcurrency's constructor. The root cause is C++'s unspecified initialization order of global/static objects across translation units: the global AdaptiveMaxConcurrency instance may be constructed before its dependent class static std::string member, leading to undefined memory access. The solution uses function-local static variables (Meyers' Singleton) to enforce the correct initialization order, eliminating the crash by guaranteeing the dependent static member is initialized prior to the global object.

To Reproduce

Expected behavior

Versions
OS: CentOS 7.9
Compiler: GCC 11.2.1
brpc: 1.16
protobuf: 21.12

Additional context/screenshots

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions