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 7831d5d1 UTF-8 recovery loop end-of-input handling (#695)
7831d5d1 is described below

commit 7831d5d196e0ccdc0e7437bb0fead37aba186e8f
Author: jmestwa-coder <[email protected]>
AuthorDate: Mon Jun 1 07:11:23 2026 +0530

    UTF-8 recovery loop end-of-input handling (#695)
---
 src/main/cpp/charsetencoder.cpp                 |  7 +++-
 src/test/cpp/helpers/charsetencodertestcase.cpp | 45 +++++++++++++++++++++++++
 2 files changed, 51 insertions(+), 1 deletion(-)

diff --git a/src/main/cpp/charsetencoder.cpp b/src/main/cpp/charsetencoder.cpp
index f153008d..ce93dc9d 100644
--- a/src/main/cpp/charsetencoder.cpp
+++ b/src/main/cpp/charsetencoder.cpp
@@ -623,7 +623,12 @@ void CharsetEncoder::encode(CharsetEncoderPtr& enc,
 #elif LOG4CXX_LOGCHAR_IS_UTF8
 
                //  advance past this character and all continuation characters
-               while ((*(++iter) & 0xC0) == 0x80);
+               do
+               {
+                       ++iter;
+               }
+               while (iter != src.end() &&
+                          (*iter & 0xC0) == 0x80);
 
 #else
 #error logchar is unrecognized
diff --git a/src/test/cpp/helpers/charsetencodertestcase.cpp 
b/src/test/cpp/helpers/charsetencodertestcase.cpp
index 0b86915a..8d1430e4 100644
--- a/src/test/cpp/helpers/charsetencodertestcase.cpp
+++ b/src/test/cpp/helpers/charsetencodertestcase.cpp
@@ -21,6 +21,11 @@
 #include <log4cxx/helpers/bytebuffer.h>
 #include <log4cxx/helpers/transcoder.h>
 #include <log4cxx/helpers/loglog.h>
+#include <log4cxx/helpers/outputstreamwriter.h>
+#include <log4cxx/helpers/outputstream.h>
+#include <log4cxx/helpers/fileoutputstream.h>
+#include <log4cxx/helpers/fileinputstream.h>
+#include <log4cxx/file.h>
 #include <apr.h>
 #include <apr_errno.h>
 #include <condition_variable>
@@ -38,6 +43,7 @@ LOGUNIT_CLASS(CharsetEncoderTestCase)
        LOGUNIT_TEST(encode3);
        LOGUNIT_TEST(encode4);
        LOGUNIT_TEST(encode5);
+       LOGUNIT_TEST(utf8Recovery);
        LOGUNIT_TEST(thread1);
        LOGUNIT_TEST_SUITE_END();
 
@@ -235,6 +241,45 @@ public:
                }
        }
 
+       /**
+        * Regression test: write malformed UTF-8 through OutputStreamWriter
+        * using a non-trivial encoder and assert the replacement character
+        * is emitted (Transcoder::LOSSCHAR). This is deterministic and does
+        * not rely on process crash.
+        */
+       void utf8Recovery()
+       {
+               File(LOG4CXX_STR("output")).mkdirs();
+
+               // Use FileOutputStream + OutputStreamWriter with US-ASCII 
encoder
+               OutputStreamPtr fos = FileOutputStreamPtr(
+                       new 
FileOutputStream(LOG4CXX_STR("output/utf8Recovery.txt")));
+               CharsetEncoderPtr 
enc(CharsetEncoder::getEncoder(LOG4CXX_STR("US-ASCII")));
+               OutputStreamWriterPtr osw = OutputStreamWriterPtr(
+                       new OutputStreamWriter(fos, enc));
+
+               // Minimal malformed UTF-8: a single lead byte 0xC2 with no 
continuation
+               LogString s;
+               s.append(1, static_cast<logchar>(0xC2));
+
+               // Write and flush
+               osw->write(s);
+               osw->flush();
+               fos->close();
+
+               // Read back the raw byte and assert the encoder emitted 
LOSSCHAR.
+               InputStreamPtr fis = FileInputStreamPtr(
+                       new 
FileInputStream(LOG4CXX_STR("output/utf8Recovery.txt")));
+               char raw[4] = { 0, 0, 0, 0 };
+               ByteBuffer buf(raw, sizeof(raw));
+               int read = fis->read(buf);
+
+               LOGUNIT_ASSERT_EQUAL(1, read);
+               LOGUNIT_ASSERT_EQUAL((size_t)1, buf.position());
+               LOGUNIT_ASSERT_EQUAL((unsigned char) Transcoder::LOSSCHAR,
+                       (unsigned char) raw[0]);
+       }
+
        class ThreadPackage
        {
                public:

Reply via email to