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

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

commit a0d7191cacb911fabd2a439f984f03d0155a037e
Author: Stephen Webb <[email protected]>
AuthorDate: Tue Mar 10 18:50:45 2026 +1100

    Prevent abnormal termination when the XML configuration file has recursive 
references
---
 src/test/cpp/asyncappendertestcase.cpp           | 70 +++++++++++++++++++-----
 src/test/resources/input/xml/recursiveConfig.xml | 38 +++++++++++++
 2 files changed, 93 insertions(+), 15 deletions(-)

diff --git a/src/test/cpp/asyncappendertestcase.cpp 
b/src/test/cpp/asyncappendertestcase.cpp
index 2c474528..276d6705 100644
--- a/src/test/cpp/asyncappendertestcase.cpp
+++ b/src/test/cpp/asyncappendertestcase.cpp
@@ -48,7 +48,7 @@ struct MyStruct
 {
        int value;
 };
-using OutputStreamType = std::basic_ostream<log4cxx::logchar>;
+using OutputStreamType = std::basic_ostream<LOG4CXX_NS::logchar>;
 OutputStreamType& operator<<(OutputStreamType& stream, const MyStruct& data)
 {
        stream << LOG4CXX_STR("[MyStruct value: ") << data.value << 
LOG4CXX_STR("]");
@@ -56,13 +56,13 @@ OutputStreamType& operator<<(OutputStreamType& stream, 
const MyStruct& data)
 }
 
 #if FMT_VERSION >= (9 * 10000)
-template <> struct fmt::formatter<MyStruct, log4cxx::logchar> : 
fmt::basic_ostream_formatter<log4cxx::logchar> {};
+template <> struct fmt::formatter<MyStruct, LOG4CXX_NS::logchar> : 
fmt::basic_ostream_formatter<LOG4CXX_NS::logchar> {};
 #endif
 #endif
 
-using namespace log4cxx;
-using namespace log4cxx::helpers;
-using namespace log4cxx::spi;
+using namespace LOG4CXX_NS;
+using namespace LOG4CXX_NS::helpers;
+using namespace LOG4CXX_NS::spi;
 
 class NullPointerAppender : public AppenderSkeleton
 {
@@ -75,7 +75,7 @@ class NullPointerAppender : public AppenderSkeleton
                /**
                 * @{inheritDoc}
                 */
-               void append(const spi::LoggingEventPtr&, 
log4cxx::helpers::Pool&) override
+               void append(const spi::LoggingEventPtr&, 
LOG4CXX_NS::helpers::Pool&) override
                {
                        throw RuntimeException(LOG4CXX_STR("Intentional 
Exception"));
                }
@@ -108,7 +108,7 @@ class BlockableVectorAppender : public VectorAppender
                /**
                 * {@inheritDoc}
                 */
-               void append(const spi::LoggingEventPtr& event, 
log4cxx::helpers::Pool& p) override
+               void append(const spi::LoggingEventPtr& event, 
LOG4CXX_NS::helpers::Pool& p) override
                {
                        std::lock_guard<std::mutex> lock( blocker );
                        VectorAppender::append(event, p);
@@ -128,7 +128,7 @@ LOG4CXX_PTR_DEF(BlockableVectorAppender);
 class LoggingVectorAppender : public VectorAppender
 {
        LoggerInstancePtr logger{ "LoggingVectorAppender" };
-       void append(const spi::LoggingEventPtr& event, log4cxx::helpers::Pool& 
p) override
+       void append(const spi::LoggingEventPtr& event, 
LOG4CXX_NS::helpers::Pool& p) override
        {
                auto& lsMsg = event->getRenderedMessage();
                VectorAppender::append(event, p);
@@ -165,6 +165,7 @@ class AsyncAppenderTestCase : public 
AppenderSkeletonTestCase
 #if LOG4CXX_HAS_DOMCONFIGURATOR
                LOGUNIT_TEST(testXMLConfiguration);
                LOGUNIT_TEST(testAsyncLoggerXML);
+               LOGUNIT_TEST(testRecursiveConfiguration);
 #endif
                LOGUNIT_TEST(testAsyncLoggerProperties);
 #if LOG4CXX_ASYNC_BUFFER_SUPPORTS_FMT
@@ -503,7 +504,7 @@ class AsyncAppenderTestCase : public 
AppenderSkeletonTestCase
                        LOGUNIT_ASSERT_EQUAL(levelCount[Level::getError()], 1);
                        LOGUNIT_ASSERT_EQUAL(discardEvent->getLevel(), 
Level::getError());
                        // Check the discard message does not have location info
-                       
LOGUNIT_ASSERT_EQUAL(log4cxx::spi::LocationInfo::getLocationUnavailable().getClassName(),
+                       
LOGUNIT_ASSERT_EQUAL(LOG4CXX_NS::spi::LocationInfo::getLocationUnavailable().getClassName(),
                                
discardEvent->getLocationInformation().getClassName());
                }
 
@@ -585,7 +586,7 @@ class AsyncAppenderTestCase : public 
AppenderSkeletonTestCase
 
                        // Check configuration is as expected
                        auto  root = Logger::getRootLogger();
-                       auto asyncAppender = 
log4cxx::cast<AsyncAppender>(root->getAppender(LOG4CXX_STR("ASYNC")));
+                       auto asyncAppender = 
LOG4CXX_NS::cast<AsyncAppender>(root->getAppender(LOG4CXX_STR("ASYNC")));
                        LOGUNIT_ASSERT(asyncAppender);
                        LOGUNIT_ASSERT_EQUAL(100, 
asyncAppender->getBufferSize());
                        LOGUNIT_ASSERT_EQUAL(false, 
asyncAppender->getBlocking());
@@ -602,7 +603,7 @@ class AsyncAppenderTestCase : public 
AppenderSkeletonTestCase
                        asyncAppender->close();
 
                        // Check all message were received
-                       auto vectorAppender = 
log4cxx::cast<VectorAppender>(asyncAppender->getAppender(LOG4CXX_STR("VECTOR")));
+                       auto vectorAppender = 
LOG4CXX_NS::cast<VectorAppender>(asyncAppender->getAppender(LOG4CXX_STR("VECTOR")));
                        LOGUNIT_ASSERT(vectorAppender);
                        auto& v = vectorAppender->getVector();
                        LOGUNIT_ASSERT_EQUAL(LEN, v.size());
@@ -619,7 +620,7 @@ class AsyncAppenderTestCase : public 
AppenderSkeletonTestCase
                        auto  root = Logger::getRootLogger();
                        auto appenders = root->getAllAppenders();
                        LOGUNIT_ASSERT_EQUAL(1, int(appenders.size()));
-                       auto asyncAppender = 
log4cxx::cast<AsyncAppender>(appenders.front());
+                       auto asyncAppender = 
LOG4CXX_NS::cast<AsyncAppender>(appenders.front());
                        LOGUNIT_ASSERT(asyncAppender);
 
                        // Log some messages
@@ -631,12 +632,51 @@ class AsyncAppenderTestCase : public 
AppenderSkeletonTestCase
                        asyncAppender->close();
 
                        // Check all message were received
-                       auto vectorAppender = 
log4cxx::cast<VectorAppender>(asyncAppender->getAppender(LOG4CXX_STR("VECTOR")));
+                       auto vectorAppender = 
LOG4CXX_NS::cast<VectorAppender>(asyncAppender->getAppender(LOG4CXX_STR("VECTOR")));
                        LOGUNIT_ASSERT(vectorAppender);
                        auto& v = vectorAppender->getVector();
                        LOGUNIT_ASSERT_EQUAL(LEN, v.size());
                        LOGUNIT_ASSERT(vectorAppender->isClosed());
                }
+
+               void testRecursiveConfiguration()
+               {
+                       // Configure Log4cxx
+                       auto status = 
xml::DOMConfigurator::configure("input/xml/recursiveConfig.xml");
+                       LOGUNIT_ASSERT_EQUAL(status, 
spi::ConfigurationStatus::Configured);
+
+                       // Check configuration is as expected
+                       auto  root = Logger::getRootLogger();
+                       auto appenders = root->getAllAppenders();
+                       LOGUNIT_ASSERT_EQUAL(1, int(appenders.size()));
+                       auto asyncAppender = 
LOG4CXX_NS::cast<AsyncAppender>(appenders.front());
+                       LOGUNIT_ASSERT(asyncAppender);
+                       VectorAppenderPtr vectorAppender;
+                       for (auto attachedAppender : 
asyncAppender->getAllAppenders())
+                       {
+                               if (auto async2 = 
LOG4CXX_NS::cast<AsyncAppender>(attachedAppender))
+                               {
+                                       for (auto appender : 
async2->getAllAppenders())
+                                               if (vectorAppender = 
LOG4CXX_NS::cast<VectorAppender>(appender))
+                                                       break;
+                               }
+                       }
+                       LOGUNIT_ASSERT(vectorAppender);
+
+                       // Log some messages
+                       size_t LEN = 20;
+                       for (size_t i = 0; i < LEN; i++)
+                       {
+                               LOG4CXX_INFO_ASYNC(root, "message" << i);
+                       }
+                       std::this_thread::sleep_for( std::chrono::milliseconds( 
100 ) );
+                       asyncAppender->close();
+
+                       // Check all message were received
+                       auto& v = vectorAppender->getVector();
+                       LOGUNIT_ASSERT_EQUAL(LEN, v.size());
+                       LOGUNIT_ASSERT(vectorAppender->isClosed());
+               }
 #endif
 
                void testAsyncLoggerProperties()
@@ -649,7 +689,7 @@ class AsyncAppenderTestCase : public 
AppenderSkeletonTestCase
                        auto  root = Logger::getRootLogger();
                        auto appenders = root->getAllAppenders();
                        LOGUNIT_ASSERT_EQUAL(1, int(appenders.size()));
-                       auto asyncAppender = 
log4cxx::cast<AsyncAppender>(appenders.front());
+                       auto asyncAppender = 
LOG4CXX_NS::cast<AsyncAppender>(appenders.front());
                        LOGUNIT_ASSERT(asyncAppender);
 
                        // Log some messages
@@ -661,7 +701,7 @@ class AsyncAppenderTestCase : public 
AppenderSkeletonTestCase
                        asyncAppender->close();
 
                        // Check all message were received
-                       auto vectorAppender = 
log4cxx::cast<VectorAppender>(asyncAppender->getAppender(LOG4CXX_STR("VECTOR")));
+                       auto vectorAppender = 
LOG4CXX_NS::cast<VectorAppender>(asyncAppender->getAppender(LOG4CXX_STR("VECTOR")));
                        LOGUNIT_ASSERT(vectorAppender);
                        auto& v = vectorAppender->getVector();
                        LOGUNIT_ASSERT_EQUAL(LEN, v.size());
diff --git a/src/test/resources/input/xml/recursiveConfig.xml 
b/src/test/resources/input/xml/recursiveConfig.xml
new file mode 100644
index 00000000..716b04c4
--- /dev/null
+++ b/src/test/resources/input/xml/recursiveConfig.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements.  See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+-->
+
+<log4j:configuration xmlns:log4j='http://jakarta.apache.org/log4j/'>
+
+  <appender name="VECTOR" class="org.apache.log4j.VectorAppender"/>
+
+  <appender name="ASYNC1" class="org.apache.log4j.AsyncAppender">
+    <appender-ref ref="ASYNC2"/>
+    <appender-ref ref="VECTOR"/>
+  </appender>
+
+  <appender name="ASYNC2" class="org.apache.log4j.AsyncAppender">
+    <appender-ref ref="ASYNC1"/>
+  </appender>
+
+  <root>
+    <level value="DEBUG"/>
+    <appender-ref ref="ASYNC2" />
+  </root>
+</log4j:configuration>

Reply via email to