Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

2 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

staticinit

staticinit is a Clang LibTooling-based utility that helps identify C++ objects that may participate in the Static Initialization Order Fiasco (SIOF).

The tool analyzes source files using a compile_commands.json compilation database and reports:

  • global variables with dynamic initialization;
  • static data members with dynamic initialization;
  • objects initialized through a non-trivial default constructor;
  • references to other global variables or static data members found in initialization expressions;
  • whether the referenced variable is dynamically initialized or statically initialized;
  • whether a dynamically initialized dependency is defined earlier or later in the same translation unit.

Features

  • Uses the project's compilation database (compile_commands.json).
  • Analyzes a single source file or an entire project.
  • Parallel processing using multiple worker threads.
  • Colored output by default.
  • Directory exclusion support.
  • Detection of potential initialization-order dependencies.

Requirements

Ubuntu 24.04

Install the required packages:

sudo apt update

sudo apt install \
    clang-18 \
    clang-tools-18 \
    llvm-18-dev \
    libclang-18-dev \
    libclang-cpp18-dev \
    cmake \
    ninja-build

Building

cmake -S . -B build
cmake --build build

The resulting executable is:

build/staticinit

Generating compile_commands.json for your project

With CMake

In your project source directory:

cmake -S . -B build -DCMAKE_EXPORT_COMPILE_COMMANDS=ON

The compilation database should be generated as:

build/compile_commands.json

Usage

Still in your project source directory:

Analyze the Entire Project

./build/staticinit -p build

Analyze Specific Files

./build/staticinit -p build src/foo.cpp
./build/staticinit -p build src/foo.cpp src/bar.cpp

Parallel Analysis

Use all available hardware threads (default):

./build/staticinit -p build

Specify the number of worker threads:

./build/staticinit -p build -j 2

Ignore Directories

./build/staticinit -p build -i third_party -i generated

All source files and declarations originating from these directories (and their subdirectories) will be ignored.

Disable Colored Output

Colored output is enabled by default.

./build/staticinit p build -n

Default colors:

  • blue: analyzed variable name;
  • magenta: initialization expression;
  • yellow: legitimate references to other global/static variables.
  • red: spurious references to other global/static variables.

Example

Source code:

std::string a;

std::string b = a + " world";

std::string c = d;

std::string d;

Output:

foo.cpp:1:13: global: a: std::string
  init: <default constructor>

foo.cpp:3:13: global: b: std::string
  init: a + " world"
  references global/static:
    - a: std::string [same TU, before]

foo.cpp:5:13: global: c: std::string
  init: d
  references global/static:
    - d: std::string [same TU, after]

foo.cpp:7:13: global: d: std::string
  init: <default constructor>

Output Interpretation

Default Constructor Initialization

init: <default constructor>

Indicates that no explicit initializer is present, but a non-trivial constructor will be executed before main().

Safe Dependency

[same TU, before]

The referenced variable is defined earlier in the same translation unit.

[same TU, before]

The referenced variable has a constant(static) initialization

Suspicious Dependency

[same TU, after]

The referenced variable is defined later in the same translation unit.

This may indicate an initialization-order problem.

External or Unknown Dependency

[not detected as dynamic init in this TU]

The referenced variable is either:

  • defined in another translation unit;
  • not detected as dynamically initialized;
  • filtered out by the tool.

This situation generally deserves manual inspection.

Limitations

The tool detects dependencies directly visible in initialization expressions.

Example:

std::string b = a + "x";

The dependency on a is detected.

However:

std::string b = MakeString();

If MakeString() accesses a global variable internally, the dependency is not detected.

The current implementation focuses on dependencies explicitly visible in the AST of initialization expressions.

Typical Use Cases

  • Investigating startup crashes occurring before main().
  • Finding potential Static Initialization Order Fiasco issues.
  • Auditing large legacy codebases.
  • Reducing startup-time complexity.
  • Preparing code for migration to constexpr, constinit, or function-local statics.
  • Reviewing global state introduced by new code.

Author

Christophe Meynard

License

SPDX-License-Identifier: GPL-2.0-only

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages