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 56844c7c Prevent rollover failure with short file name patterns (#671)
56844c7c is described below

commit 56844c7c81c759b532802c06321f742d98d27a6f
Author: jmestwa-coder <[email protected]>
AuthorDate: Fri May 15 06:49:17 2026 +0530

    Prevent rollover failure with short file name patterns (#671)
---
 src/main/cpp/fixedwindowrollingpolicy.cpp     |  4 +--
 src/test/cpp/rolling/manualrollingtest.cpp    | 18 ++++++++++
 src/test/cpp/rolling/sizebasedrollingtest.cpp | 47 ++++++++++++++++++++++++++-
 3 files changed, 66 insertions(+), 3 deletions(-)

diff --git a/src/main/cpp/fixedwindowrollingpolicy.cpp 
b/src/main/cpp/fixedwindowrollingpolicy.cpp
index 89aec4c6..4f8a442f 100644
--- a/src/main/cpp/fixedwindowrollingpolicy.cpp
+++ b/src/main/cpp/fixedwindowrollingpolicy.cpp
@@ -265,11 +265,11 @@ bool FixedWindowRollingPolicy::purge(int lowIndex, int 
highIndex, Pool& p) const
 
        LogString lowFilename(buf);
 
-       if (lowFilename.compare(lowFilename.length() - 3, 3, 
LOG4CXX_STR(".gz")) == 0)
+       if (StringHelper::endsWith(lowFilename, LOG4CXX_STR(".gz")))
        {
                suffixLength = 3;
        }
-       else if (lowFilename.compare(lowFilename.length() - 4, 4, 
LOG4CXX_STR(".zip")) == 0)
+       else if (StringHelper::endsWith(lowFilename, LOG4CXX_STR(".zip")))
        {
                suffixLength = 4;
        }
diff --git a/src/test/cpp/rolling/manualrollingtest.cpp 
b/src/test/cpp/rolling/manualrollingtest.cpp
index 2ca4cca6..50bd6681 100644
--- a/src/test/cpp/rolling/manualrollingtest.cpp
+++ b/src/test/cpp/rolling/manualrollingtest.cpp
@@ -54,6 +54,7 @@ LOGUNIT_CLASS(ManualRollingTest)
        //           LOGUNIT_TEST(test3);
        LOGUNIT_TEST(test4);
        LOGUNIT_TEST(test5);
+       LOGUNIT_TEST(testShortFileNamePattern);
        LOGUNIT_TEST(create_directories);
        LOGUNIT_TEST_SUITE_END();
 
@@ -167,6 +168,23 @@ public:
                                File("witness/rolling/sbr-test2.1")));
        }
 
+       void testShortFileNamePattern()
+       {
+               FixedWindowRollingPolicyPtr policy = 
FixedWindowRollingPolicyPtr(new FixedWindowRollingPolicy());
+               policy->setMinIndex(0);
+               policy->setMaxIndex(1);
+               policy->setFileNamePattern(LOG4CXX_STR("%i"));
+               policy->activateOptions();
+
+               Pool pool;
+               RolloverDescriptionPtr desc = policy->rollover(
+                               
LOG4CXX_STR("output/manual-short-pattern-active.log"),
+                               false,
+                               pool);
+
+               LOGUNIT_ASSERT(desc != NULL);
+       }
+
        /**
         * Same as testBasic but also with GZ compression.
         */
diff --git a/src/test/cpp/rolling/sizebasedrollingtest.cpp 
b/src/test/cpp/rolling/sizebasedrollingtest.cpp
index f6001cfc..ef3a6dfe 100644
--- a/src/test/cpp/rolling/sizebasedrollingtest.cpp
+++ b/src/test/cpp/rolling/sizebasedrollingtest.cpp
@@ -56,6 +56,7 @@ LOGUNIT_CLASS(SizeBasedRollingTest)
        LOGUNIT_TEST(test4);
        LOGUNIT_TEST(test5);
        LOGUNIT_TEST(test6);
+       LOGUNIT_TEST(testShortPatternRegression);
        LOGUNIT_TEST_SUITE_END();
 
        LoggerPtr root;
@@ -356,7 +357,51 @@ public:
                LOGUNIT_ASSERT_EQUAL(true, 
Compare::compare(File("output/sbr-test6.log"),  
File("witness/rolling/sbr-test3.log")));
        }
 
-};
+       /**
+        * Regression test for FixedWindowRollingPolicy::purge() underflow.
+        * This test uses a very short fileNamePattern ("R%i" -> "R1") which 
would
+        * trigger std::out_of_range in the original vulnerable code.
+        */
+       void testShortPatternRegression()
+       {
+               LogString activeFile = LOG4CXX_STR("output/active.log");
+               LogString rolledFile = LOG4CXX_STR("R1");
+               File(activeFile).deleteFile();
+               File(rolledFile).deleteFile();
+
+               PatternLayoutPtr layout = PatternLayoutPtr(new 
PatternLayout(LOG4CXX_STR("%m\n")));
+               RollingFileAppenderPtr rfa = RollingFileAppenderPtr(new 
RollingFileAppender());
+               rfa->setAppend(false);
+               rfa->setLayout(layout);
+               rfa->setFile(activeFile);
+
+               FixedWindowRollingPolicyPtr swrp = 
FixedWindowRollingPolicyPtr(new FixedWindowRollingPolicy());
+               SizeBasedTriggeringPolicyPtr sbtp = 
SizeBasedTriggeringPolicyPtr(new SizeBasedTriggeringPolicy());
 
+               sbtp->setMaxFileSize(5); // Very small to trigger rollover
+               swrp->setMinIndex(1);
+               swrp->setFileNamePattern(LOG4CXX_STR("R%i"));
+               swrp->activateOptions();
+
+               rfa->setRollingPolicy(swrp);
+               rfa->setTriggeringPolicy(sbtp);
+               rfa->activateOptions();
+               root->addAppender(rfa);
+
+               // First log: goes to active.log, size becomes > 5
+               LOG4CXX_INFO(logger, LOG4CXX_STR("123456"));
+               // Second log: triggers rollover
+               LOG4CXX_INFO(logger, LOG4CXX_STR("next"));
+
+               // In the vulnerable code, rollover would fail due to 
std::out_of_range
+               // and the rolled file would not exist.
+               LOGUNIT_ASSERT(File(rolledFile).exists());
+
+               // Cleanup
+               File(activeFile).deleteFile();
+               File(rolledFile).deleteFile();
+       }
+
+};
 
 LOGUNIT_TEST_SUITE_REGISTRATION(SizeBasedRollingTest);

Reply via email to