From 0ff197d4061f96b9a6b39af06264d4c73843b3fc Mon Sep 17 00:00:00 2001 From: Andrew Noyes Date: Sat, 30 Aug 2025 17:57:16 -0400 Subject: [PATCH] Fix static initialization order fiasco --- src/metric.cpp | 54 +++++++++++++++++++++++++++----------------------- 1 file changed, 29 insertions(+), 25 deletions(-) diff --git a/src/metric.cpp b/src/metric.cpp index 9e12a38..f131bcf 100644 --- a/src/metric.cpp +++ b/src/metric.cpp @@ -23,8 +23,6 @@ #include "format.hpp" -// TODO fix static initialization order fiasco - // Verify that malloc provides sufficient alignment for atomic 128-bit // operations static_assert(__STDCPP_DEFAULT_NEW_ALIGNMENT__ >= 16, @@ -193,15 +191,27 @@ struct Histogram::State { struct Metric { static std::mutex mutex; - // Two-level map: name -> Family - static std::unordered_map::State>> - counterFamilies; - static std::unordered_map::State>> - gaugeFamilies; - static std::unordered_map::State>> - histogramFamilies; + // Function-local statics to avoid static initialization order fiasco + static auto &get_counter_families() { + static std::unordered_map::State>> + counterFamilies; + return counterFamilies; + } + + static auto &get_gauge_families() { + static std::unordered_map::State>> + gaugeFamilies; + return gaugeFamilies; + } + + static auto &get_histogram_families() { + static std::unordered_map::State>> + histogramFamilies; + return histogramFamilies; + } // Thread cleanup for per-family thread-local storage struct ThreadInit { @@ -214,7 +224,7 @@ struct Metric { auto thread_id = std::this_thread::get_id(); // Accumulate counter families - for (auto &[name, family] : counterFamilies) { + for (auto &[name, family] : Metric::get_counter_families()) { auto thread_it = family->perThreadState.find(thread_id); if (thread_it != family->perThreadState.end()) { for (auto &[labels_key, instance] : thread_it->second.instances) { @@ -236,7 +246,7 @@ struct Metric { } // Accumulate histogram families - for (auto &[name, family] : histogramFamilies) { + for (auto &[name, family] : Metric::get_histogram_families()) { auto thread_it = family->perThreadState.find(thread_id); if (thread_it != family->perThreadState.end()) { for (auto &[labels_key, instance] : thread_it->second.instances) { @@ -490,7 +500,7 @@ Family create_counter(std::string name, std::string help) { name.c_str()); std::unique_lock _{Metric::mutex}; - auto &familyPtr = Metric::counterFamilies[name]; + auto &familyPtr = Metric::get_counter_families()[name]; if (!familyPtr) { familyPtr = std::make_unique::State>(); familyPtr->name = std::move(name); @@ -511,7 +521,7 @@ Family create_gauge(std::string name, std::string help) { name.c_str()); std::unique_lock _{Metric::mutex}; - auto &familyPtr = Metric::gaugeFamilies[name]; + auto &familyPtr = Metric::get_gauge_families()[name]; if (!familyPtr) { familyPtr = std::make_unique::State>(); familyPtr->name = std::move(name); @@ -533,7 +543,7 @@ Family create_histogram(std::string name, std::string help, name.c_str()); std::unique_lock _{Metric::mutex}; - auto &familyPtr = Metric::histogramFamilies[name]; + auto &familyPtr = Metric::get_histogram_families()[name]; if (!familyPtr) { familyPtr = std::make_unique::State>(); familyPtr->name = std::move(name); @@ -724,7 +734,7 @@ std::span render(ArenaAllocator &arena) { }; // Render counters - for (const auto &[name, family] : Metric::counterFamilies) { + for (const auto &[name, family] : Metric::get_counter_families()) { output.push_back( format(arena, "# HELP %s %s\n", name.c_str(), family->help.c_str())); output.push_back(format(arena, "# TYPE %s counter\n", name.c_str())); @@ -777,7 +787,7 @@ std::span render(ArenaAllocator &arena) { } // Render gauges - for (const auto &[name, family] : Metric::gaugeFamilies) { + for (const auto &[name, family] : Metric::get_gauge_families()) { output.push_back( format(arena, "# HELP %s %s\n", name.c_str(), family->help.c_str())); output.push_back(format(arena, "# TYPE %s gauge\n", name.c_str())); @@ -810,7 +820,7 @@ std::span render(ArenaAllocator &arena) { } // Render histograms - for (const auto &[name, family] : Metric::histogramFamilies) { + for (const auto &[name, family] : Metric::get_histogram_families()) { output.push_back( format(arena, "# HELP %s %s\n", name.c_str(), family->help.c_str())); output.push_back(format(arena, "# TYPE %s histogram\n", name.c_str())); @@ -995,12 +1005,6 @@ void Family::register_callback( // Static member definitions std::mutex Metric::mutex; -std::unordered_map::State>> - Metric::counterFamilies; -std::unordered_map::State>> - Metric::gaugeFamilies; -std::unordered_map::State>> - Metric::histogramFamilies; thread_local Metric::ThreadInit Metric::thread_init; } // namespace metric