From 6152a741174589a91f7f47b53ff81c36a69ab461 Mon Sep 17 00:00:00 2001 From: Mikhail Aksenov Date: Tue, 21 Jul 2026 15:41:11 +0000 Subject: [PATCH] Survive static destruction order in AWSLogging accessors The logger is held in two namespace-scope shared_ptr statics. AWS clients owned by other translation units can be destroyed after these statics (the order of static destruction across translation units is unspecified) and may still call GetLogSystem()/Push/PopLogger while unwinding at process exit. Once the shared_ptrs have been destroyed, those calls touch freed objects. Move the two shared_ptrs into a LoggingSet struct guarded by a trivially destructible bool flag, LoggingSetAlive, which stays readable until the very end of the process. ~LoggingSet clears the flag; afterwards the accessors behave as if no logger is installed instead of reading the destroyed members. --- .../source/utils/logging/AWSLogging.cpp | 48 +++++++++++++++---- 1 file changed, 39 insertions(+), 9 deletions(-) diff --git a/src/aws-cpp-sdk-core/source/utils/logging/AWSLogging.cpp b/src/aws-cpp-sdk-core/source/utils/logging/AWSLogging.cpp index 3163e19d9ca1..1709dcd7c1d6 100644 --- a/src/aws-cpp-sdk-core/source/utils/logging/AWSLogging.cpp +++ b/src/aws-cpp-sdk-core/source/utils/logging/AWSLogging.cpp @@ -14,8 +14,28 @@ using namespace Aws::Utils; using namespace Aws::Utils::Logging; -static std::shared_ptr AWSLogSystem(nullptr); -static std::shared_ptr OldLogger(nullptr); +namespace { + +// AWS clients owned by other globals can be destroyed after this translation +// unit's statics (static destruction order across translation units is +// unspecified) and still log through GetLogSystem() while unwinding. The flag +// is trivially destructible, so it stays readable until the very end of the +// process; once ~LoggingSet has cleared it, the accessors below behave as +// if no logger is installed instead of touching the destroyed shared_ptrs. +bool LoggingSetAlive = true; + +struct LoggingSet { + std::shared_ptr AWSLogSystem; + std::shared_ptr OldLogger; + + ~LoggingSet() { + LoggingSetAlive = false; + } +}; + +LoggingSet LogSet; + +} // anonymous namespace namespace Aws { @@ -24,7 +44,9 @@ namespace Utils namespace Logging { void InitializeAWSLogging(const std::shared_ptr &logSystem) { - AWSLogSystem = logSystem; + if (LoggingSetAlive) { + LogSet.AWSLogSystem = logSystem; + } } void ShutdownAWSLogging(void) { @@ -33,23 +55,31 @@ void ShutdownAWSLogging(void) { // so this is a hack to let all other threads finish their log statement after getting a LogSystem pointer // otherwise we would need to perform ref-counting on each logging statement std::this_thread::sleep_for(std::chrono::milliseconds(1)); - OldLogger.reset(); + if (LoggingSetAlive) { + LogSet.OldLogger.reset(); + } } LogSystemInterface *GetLogSystem() { - return AWSLogSystem.get(); + return LoggingSetAlive ? LogSet.AWSLogSystem.get() : nullptr; } void PushLogger(const std::shared_ptr &logSystem) { - OldLogger = AWSLogSystem; - AWSLogSystem = logSystem; + if (!LoggingSetAlive) { + return; + } + LogSet.OldLogger = LogSet.AWSLogSystem; + LogSet.AWSLogSystem = logSystem; } void PopLogger() { - AWSLogSystem = OldLogger; - OldLogger = nullptr; + if (!LoggingSetAlive) { + return; + } + LogSet.AWSLogSystem = LogSet.OldLogger; + LogSet.OldLogger = nullptr; } } // namespace Logging