This is an automated email from the ASF dual-hosted git repository.

swebb2066 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/logging-log4cxx.git


The following commit(s) were added to refs/heads/master by this push:
     new 86ea0a77 Prevent undefined behaviour when reconfiguring after 
LogManager::shutdown (#504)
86ea0a77 is described below

commit 86ea0a77c8dfe6466358536db2755f3473347e8a
Author: Stephen Webb <[email protected]>
AuthorDate: Wed Jul 2 09:37:32 2025 +1000

    Prevent undefined behaviour when reconfiguring after LogManager::shutdown 
(#504)
---
 .github/workflows/log4cxx-windows-static.yml       |  6 +-
 .github/workflows/log4cxx-windows.yml              |  6 +-
 src/main/cpp/aprinitializer.cpp                    | 28 ++-------
 src/main/cpp/domconfigurator.cpp                   | 68 ++++++----------------
 src/main/cpp/filewatchdog.cpp                      |  5 ++
 src/main/cpp/logmanager.cpp                        |  1 -
 src/main/cpp/optionconverter.cpp                   | 22 +++++--
 src/main/cpp/propertyconfigurator.cpp              | 29 ++++-----
 src/main/include/log4cxx/helpers/aprinitializer.h  |  3 +-
 src/main/include/log4cxx/helpers/filewatchdog.h    |  5 ++
 src/main/include/log4cxx/helpers/singletonholder.h |  7 +++
 src/main/include/log4cxx/propertyconfigurator.h    |  5 +-
 src/main/include/log4cxx/xml/domconfigurator.h     |  1 -
 src/site/markdown/change-report-gh.md              |  4 ++
 14 files changed, 84 insertions(+), 106 deletions(-)

diff --git a/.github/workflows/log4cxx-windows-static.yml 
b/.github/workflows/log4cxx-windows-static.yml
index 4712728c..04a08f33 100644
--- a/.github/workflows/log4cxx-windows-static.yml
+++ b/.github/workflows/log4cxx-windows-static.yml
@@ -24,12 +24,12 @@ jobs:
     strategy:
       fail-fast: false
       matrix:
-        name: [windows-2019, windows-2022]
+        name: [windows-2022, windows-2025]
         include:
-          - name: windows-2019
-            os: windows-2019
           - name: windows-2022
             os: windows-2022
+          - name: windows-2025
+            os: windows-2025
 
     steps:
     - uses: actions/checkout@v4
diff --git a/.github/workflows/log4cxx-windows.yml 
b/.github/workflows/log4cxx-windows.yml
index 69ae88bd..393d2cd4 100644
--- a/.github/workflows/log4cxx-windows.yml
+++ b/.github/workflows/log4cxx-windows.yml
@@ -24,12 +24,12 @@ jobs:
     strategy:
       fail-fast: false
       matrix:
-        name: [windows-2019, windows-2022]
+        name: [windows-2022, windows-2025]
         include:
-          - name: windows-2019
-            os: windows-2019
           - name: windows-2022
             os: windows-2022
+          - name: windows-2025
+            os: windows-2025
 
     steps:
     - uses: actions/checkout@v4
diff --git a/src/main/cpp/aprinitializer.cpp b/src/main/cpp/aprinitializer.cpp
index a4346e72..8e62af21 100644
--- a/src/main/cpp/aprinitializer.cpp
+++ b/src/main/cpp/aprinitializer.cpp
@@ -52,7 +52,6 @@ struct APRInitializer::APRInitializerPrivate{
 
        apr_pool_t* p;
        std::mutex mutex;
-       std::list<FileWatchdog*> watchdogs;
        log4cxx_time_t startTime;
        apr_threadkey_t* tlsKey;
        std::vector<IdentifiedObject> objects;
@@ -104,7 +103,6 @@ APRInitializer::APRInitializer() :
 
 APRInitializer::~APRInitializer()
 {
-       stopWatchDogs();
        isDestructed = true;
 #if APR_HAS_THREADS
        std::lock_guard<std::mutex> lock(m_priv->mutex);
@@ -112,22 +110,11 @@ APRInitializer::~APRInitializer()
 #endif
 }
 
-void APRInitializer::stopWatchDogs()
-{
-       std::lock_guard<std::mutex> lock(m_priv->mutex);
-
-       while (!m_priv->watchdogs.empty())
-       {
-               m_priv->watchdogs.back()->stop();
-               delete m_priv->watchdogs.back();
-               m_priv->watchdogs.pop_back();
-       }
-}
-
+#if LOG4CXX_ABI_VERSION <= 15
 void APRInitializer::unregisterAll()
 {
-       getInstance().stopWatchDogs();
 }
+#endif
 
 APRInitializer& APRInitializer::getInstance()
 {
@@ -159,22 +146,15 @@ apr_threadkey_t* APRInitializer::getTlsKey()
        return getInstance().m_priv->tlsKey;
 }
 
+#if LOG4CXX_ABI_VERSION <= 15
 void APRInitializer::registerCleanup(FileWatchdog* watchdog)
 {
-       APRInitializer& instance(getInstance());
-       std::lock_guard<std::mutex> lock(instance.m_priv->mutex);
-       instance.m_priv->watchdogs.push_back(watchdog);
 }
 
 void APRInitializer::unregisterCleanup(FileWatchdog* watchdog)
 {
-       APRInitializer& instance(getInstance());
-       std::lock_guard<std::mutex> lock(instance.m_priv->mutex);
-
-       auto iter = std::find(instance.m_priv->watchdogs.begin(), 
instance.m_priv->watchdogs.end(), watchdog);
-       if (iter != instance.m_priv->watchdogs.end())
-               instance.m_priv->watchdogs.erase(iter);
 }
+#endif
 
 void APRInitializer::addObject(size_t key, const ObjectPtr& pObject)
 {
diff --git a/src/main/cpp/domconfigurator.cpp b/src/main/cpp/domconfigurator.cpp
index b8d5cc8f..ac448574 100644
--- a/src/main/cpp/domconfigurator.cpp
+++ b/src/main/cpp/domconfigurator.cpp
@@ -49,6 +49,7 @@
 #include <log4cxx/net/smtpappender.h>
 #include <log4cxx/helpers/messagebuffer.h>
 #include <log4cxx/helpers/threadutility.h>
+#include <log4cxx/helpers/singletonholder.h>
 
 #define LOG4CXX 1
 #include <log4cxx/helpers/aprinitializer.h>
@@ -89,11 +90,22 @@ class XMLWatchdog  : public FileWatchdog
                        DOMConfigurator().doConfigure(file(),
                                LogManager::getLoggerRepository());
                }
+
+               static void startWatching(const File& filename, long delay)
+               {
+                       using WatchdogHolder = SingletonHolder<XMLWatchdog>;
+                       auto pHolder = 
APRInitializer::getOrAddUnique<WatchdogHolder>
+                               ( [&filename]() -> ObjectPtr
+                                       { return 
std::make_shared<WatchdogHolder>(filename); }
+                               );
+                       auto& xdog = pHolder->value();
+                       xdog.setFile(filename);
+                       xdog.setDelay(0 < delay ? delay : 
FileWatchdog::DEFAULT_DELAY);
+                       xdog.start();
+               }
 };
 }
 }
-XMLWatchdog* DOMConfigurator::xdog = NULL;
-
 
 IMPLEMENT_LOG4CXX_OBJECT(DOMConfigurator)
 
@@ -978,19 +990,8 @@ spi::ConfigurationStatus 
DOMConfigurator::configureAndWatch(const std::string& f
 
 spi::ConfigurationStatus DOMConfigurator::configureAndWatch(const File& file, 
long delay)
 {
-       if ( xdog )
-       {
-               APRInitializer::unregisterCleanup(xdog);
-               delete xdog;
-       }
-
        spi::ConfigurationStatus status = DOMConfigurator().doConfigure(file, 
LogManager::getLoggerRepository());
-
-       xdog = new XMLWatchdog(file);
-       APRInitializer::registerCleanup(xdog);
-       xdog->setDelay(0 < delay ? delay : FileWatchdog::DEFAULT_DELAY);
-       xdog->start();
-
+       XMLWatchdog::startWatching(file, delay);
        return status;
 }
 
@@ -999,19 +1000,8 @@ spi::ConfigurationStatus 
DOMConfigurator::configureAndWatch(const File& file, lo
 spi::ConfigurationStatus DOMConfigurator::configureAndWatch(const 
std::wstring& filename, long delay)
 {
        File file(filename);
-       if ( xdog )
-       {
-               APRInitializer::unregisterCleanup(xdog);
-               delete xdog;
-       }
-
        spi::ConfigurationStatus status = DOMConfigurator().doConfigure(file, 
LogManager::getLoggerRepository());
-
-       xdog = new XMLWatchdog(file);
-       APRInitializer::registerCleanup(xdog);
-       xdog->setDelay(delay);
-       xdog->start();
-
+       XMLWatchdog::startWatching(file, delay);
        return status;
 }
 #endif
@@ -1020,19 +1010,8 @@ spi::ConfigurationStatus 
DOMConfigurator::configureAndWatch(const std::wstring&
 spi::ConfigurationStatus DOMConfigurator::configureAndWatch(const 
std::basic_string<UniChar>& filename, long delay)
 {
        File file(filename);
-       if ( xdog )
-       {
-               APRInitializer::unregisterCleanup(xdog);
-               delete xdog;
-       }
-
        spi::ConfigurationStatus status = DOMConfigurator().doConfigure(file, 
LogManager::getLoggerRepository());
-
-       xdog = new XMLWatchdog(file);
-       APRInitializer::registerCleanup(xdog);
-       xdog->setDelay(delay);
-       xdog->start();
-
+       XMLWatchdog::startWatching(file, delay);
        return status;
 }
 #endif
@@ -1041,19 +1020,8 @@ spi::ConfigurationStatus 
DOMConfigurator::configureAndWatch(const std::basic_str
 spi::ConfigurationStatus DOMConfigurator::configureAndWatch(const CFStringRef& 
filename, long delay)
 {
        File file(filename);
-       if ( xdog )
-       {
-               APRInitializer::unregisterCleanup(xdog);
-               delete xdog;
-       }
-
        spi::ConfigurationStatus status = DOMConfigurator().doConfigure(file, 
LogManager::getLoggerRepository());
-
-       xdog = new XMLWatchdog(file);
-       APRInitializer::registerCleanup(xdog);
-       xdog->setDelay(delay);
-       xdog->start();
-
+       XMLWatchdog::startWatching(file, delay);
        return status;
 }
 #endif
diff --git a/src/main/cpp/filewatchdog.cpp b/src/main/cpp/filewatchdog.cpp
index 2cd4c49f..73ffc732 100644
--- a/src/main/cpp/filewatchdog.cpp
+++ b/src/main/cpp/filewatchdog.cpp
@@ -163,3 +163,8 @@ void FileWatchdog::setDelay(long delay1){
                        );
        }
 }
+
+void FileWatchdog::setFile(const File& filename)
+{
+    m_priv->file = filename;
+}
diff --git a/src/main/cpp/logmanager.cpp b/src/main/cpp/logmanager.cpp
index 36fedd00..935154de 100644
--- a/src/main/cpp/logmanager.cpp
+++ b/src/main/cpp/logmanager.cpp
@@ -203,7 +203,6 @@ LoggerList LogManager::getCurrentLoggers()
 
 void LogManager::shutdown()
 {
-       APRInitializer::unregisterAll();
        ThreadUtility::instance()->removeAllPeriodicTasks();
        getLoggerRepository()->shutdown();
 }
diff --git a/src/main/cpp/optionconverter.cpp b/src/main/cpp/optionconverter.cpp
index 6fa7b502..f70baef3 100644
--- a/src/main/cpp/optionconverter.cpp
+++ b/src/main/cpp/optionconverter.cpp
@@ -42,6 +42,7 @@
 #endif
 #include <log4cxx/helpers/aprinitializer.h>
 #include <log4cxx/helpers/filewatchdog.h>
+#include <log4cxx/helpers/singletonholder.h>
 
 namespace LOG4CXX_NS
 {
@@ -65,6 +66,20 @@ class ConfiguratorWatchdog  : public helpers::FileWatchdog
     {
         m_config->doConfigure(file(), LogManager::getLoggerRepository());
     }
+
+       static void startWatching(const spi::ConfiguratorPtr& config, const 
File& filename, long delay)
+       {
+               using WatchdogHolder = 
helpers::SingletonHolder<ConfiguratorWatchdog>;
+               auto pHolder = 
helpers::APRInitializer::getOrAddUnique<WatchdogHolder>
+                       ( [&config, &filename]() -> helpers::ObjectPtr
+                               { return 
std::make_shared<WatchdogHolder>(config, filename); }
+                       );
+               auto& dog = pHolder->value();
+               dog.m_config = config;
+               dog.setFile(filename);
+               dog.setDelay(delay);
+               dog.start();
+       }
 };
 
 }
@@ -465,12 +480,7 @@ void OptionConverter::selectAndConfigure(const File& 
configFileName,
        }
 
        if (0 < delay)
-       {
-               auto dog = new ConfiguratorWatchdog(configurator, 
configFileName);
-               APRInitializer::registerCleanup(dog);
-               dog->setDelay(delay);
-               dog->start();
-       }
+               ConfiguratorWatchdog::startWatching(configurator, 
configFileName, delay);
        else
                configurator->doConfigure(configFileName, hierarchy);
 }
diff --git a/src/main/cpp/propertyconfigurator.cpp 
b/src/main/cpp/propertyconfigurator.cpp
index 922edac5..9586a13b 100644
--- a/src/main/cpp/propertyconfigurator.cpp
+++ b/src/main/cpp/propertyconfigurator.cpp
@@ -36,6 +36,7 @@
 #include <log4cxx/helpers/fileinputstream.h>
 #include <log4cxx/helpers/loader.h>
 #include <log4cxx/helpers/threadutility.h>
+#include <log4cxx/helpers/singletonholder.h>
 #include <log4cxx/rolling/rollingfileappender.h>
 
 #define LOG4CXX 1
@@ -67,11 +68,22 @@ class PropertyWatchdog  : public FileWatchdog
                        PropertyConfigurator().doConfigure(file(),
                                LogManager::getLoggerRepository());
                }
+
+               static void startWatching(const File& filename, long delay)
+               {
+                       using WatchdogHolder = 
SingletonHolder<PropertyWatchdog>;
+                       auto pHolder = 
APRInitializer::getOrAddUnique<WatchdogHolder>
+                               ( [&filename]() -> ObjectPtr
+                                       { return 
std::make_shared<WatchdogHolder>(filename); }
+                               );
+                       auto& pdog = pHolder->value();
+                       pdog.setFile(filename);
+                       pdog.setDelay(0 < delay ? delay : 
FileWatchdog::DEFAULT_DELAY);
+                       pdog.start();
+               }
 };
 }
 
-PropertyWatchdog* PropertyConfigurator::pdog = NULL;
-
 IMPLEMENT_LOG4CXX_OBJECT(PropertyConfigurator)
 
 PropertyConfigurator::PropertyConfigurator()
@@ -155,19 +167,8 @@ spi::ConfigurationStatus 
PropertyConfigurator::configureAndWatch(const File& con
 spi::ConfigurationStatus PropertyConfigurator::configureAndWatch(
        const File& configFilename, long delay)
 {
-       if (pdog)
-       {
-               APRInitializer::unregisterCleanup(pdog);
-               delete pdog;
-       }
-
        spi::ConfigurationStatus stat = 
PropertyConfigurator().doConfigure(configFilename, 
LogManager::getLoggerRepository());
-
-       pdog = new PropertyWatchdog(configFilename);
-       APRInitializer::registerCleanup(pdog);
-       pdog->setDelay(0 < delay ? delay : FileWatchdog::DEFAULT_DELAY);
-       pdog->start();
-
+       PropertyWatchdog::startWatching(configFilename, delay);
        return stat;
 }
 
diff --git a/src/main/include/log4cxx/helpers/aprinitializer.h 
b/src/main/include/log4cxx/helpers/aprinitializer.h
index f810127a..aab18595 100644
--- a/src/main/include/log4cxx/helpers/aprinitializer.h
+++ b/src/main/include/log4cxx/helpers/aprinitializer.h
@@ -52,6 +52,7 @@ class APRInitializer
                static apr_threadkey_t* getTlsKey();
                static bool isDestructed;
 
+#if LOG4CXX_ABI_VERSION <= 15
                /**
                 *  Register a FileWatchdog for deletion prior to termination.
                 *    FileWatchdog must be
@@ -60,6 +61,7 @@ class APRInitializer
                static void registerCleanup(FileWatchdog* watchdog);
                static void unregisterCleanup(FileWatchdog* watchdog);
                static void unregisterAll();
+#endif
                /**
                 *  Store a single instance type ObjectPtr for deletion prior 
to termination
                 */
@@ -84,7 +86,6 @@ class APRInitializer
        private: // Modifiers
                void addObject(size_t key, const ObjectPtr& pObject);
                const ObjectPtr& findOrAddObject(size_t key, 
std::function<ObjectPtr()> creator);
-               void stopWatchDogs();
        private: // Attributes
                LOG4CXX_DECLARE_PRIVATE_MEMBER_PTR(APRInitializerPrivate, 
m_priv)
        private: // Class methods
diff --git a/src/main/include/log4cxx/helpers/filewatchdog.h 
b/src/main/include/log4cxx/helpers/filewatchdog.h
index 2340fadc..710dfa2e 100644
--- a/src/main/include/log4cxx/helpers/filewatchdog.h
+++ b/src/main/include/log4cxx/helpers/filewatchdog.h
@@ -53,6 +53,11 @@ class LOG4CXX_EXPORT FileWatchdog
                */
                void setDelay(long delay);
 
+               /**
+               Change the watched file to \c filename.
+               */
+               void setFile(const File& filename);
+
                /**
                Create an asynchronous task that periodically checks for a file 
change after first calling doOnChange().
                */
diff --git a/src/main/include/log4cxx/helpers/singletonholder.h 
b/src/main/include/log4cxx/helpers/singletonholder.h
index 85783e0d..66651d99 100644
--- a/src/main/include/log4cxx/helpers/singletonholder.h
+++ b/src/main/include/log4cxx/helpers/singletonholder.h
@@ -42,6 +42,13 @@ public: // Object method stubs
        LOG4CXX_CAST_ENTRY(ThisType)
        END_LOG4CXX_CAST_MAP()
 
+public: // ...structors
+       SingletonHolder() {}
+       template <typename ... Args>
+       SingletonHolder(Args&& ... args)
+               : m_data(std::forward<Args>(args) ... )
+       {}
+
 public: // Accessors
        T& value() { return m_data; }
 };
diff --git a/src/main/include/log4cxx/propertyconfigurator.h 
b/src/main/include/log4cxx/propertyconfigurator.h
index 6f85d2b8..b5e5872b 100644
--- a/src/main/include/log4cxx/propertyconfigurator.h
+++ b/src/main/include/log4cxx/propertyconfigurator.h
@@ -64,9 +64,9 @@ support for {@link spi::Filter Filters}, custom
 {@link spi::ErrorHandler ErrorHandlers}, nested
 appenders such as the {@link AsyncAppender AsyncAppender}, etc.
 
-<h3>Appender configuration</h3>
+<h3>Configuring appenders</h3>
 
-Appender configuration syntax is:
+%Appender configuration syntax is:
 <pre>
 # For appender named <i>appenderName</i>, set its class.
 # Note: The appender name can contain dots.
@@ -391,7 +391,6 @@ class LOG4CXX_EXPORT PropertyConfigurator :
        private:
                PropertyConfigurator(const PropertyConfigurator&);
                PropertyConfigurator& operator=(const PropertyConfigurator&);
-               static PropertyWatchdog* pdog;
 }; // class PropertyConfigurator
 }  // namespace log4cxx
 
diff --git a/src/main/include/log4cxx/xml/domconfigurator.h 
b/src/main/include/log4cxx/xml/domconfigurator.h
index beea5953..16ae64b7 100644
--- a/src/main/include/log4cxx/xml/domconfigurator.h
+++ b/src/main/include/log4cxx/xml/domconfigurator.h
@@ -374,7 +374,6 @@ class LOG4CXX_EXPORT DOMConfigurator :
                //   prevent assignment or copy statements
                DOMConfigurator(const DOMConfigurator&);
                DOMConfigurator& operator=(const DOMConfigurator&);
-               static XMLWatchdog* xdog;
 
                LOG4CXX_DECLARE_PRIVATE_MEMBER_PTR(DOMConfiguratorPrivate, 
m_priv)
 };
diff --git a/src/site/markdown/change-report-gh.md 
b/src/site/markdown/change-report-gh.md
index 396e21e1..5a64f442 100644
--- a/src/site/markdown/change-report-gh.md
+++ b/src/site/markdown/change-report-gh.md
@@ -60,6 +60,10 @@ Release 1.5.0 includes the following new features:
 
 The following issues have been addressed:
 
+* Undefined behaviour when reloading a configuration file after calling 
LogManager::shutdown
+   \[[#504](https://github.com/apache/logging-log4cxx/issues/504)\]
+* Compilation error when using gcc on MacOS
+   \[[#499](https://github.com/apache/logging-log4cxx/issues/499)\]
 * It was possible for logging events to be lost when reloading a configuration 
file
    \[[#491](https://github.com/apache/logging-log4cxx/issues/491)\]
 

Reply via email to