This is an automated email from the ASF dual-hosted git repository. vy pushed a commit to branch fix/2.24.x/JTL-StackTraceStringResolver in repository https://gitbox.apache.org/repos/asf/logging-log4j2.git
commit f9402ed2f72aa0dba6fe6b2f3a796a1e7c16e6fb Author: Volkan Yazıcı <[email protected]> AuthorDate: Mon Nov 18 09:31:19 2024 +0100 Fix off-by-one in `StackTraceStringResolver` (#3194) --- .../resolver/StackTraceStringResolverTest.java | 63 ++++++++++++++++++++++ .../json/resolver/StackTraceStringResolver.java | 5 +- .../3211_fix_JTL_StackTraceStringResolver.xml | 8 +++ 3 files changed, 74 insertions(+), 2 deletions(-) diff --git a/log4j-layout-template-json-test/src/test/java/org/apache/logging/log4j/layout/template/json/resolver/StackTraceStringResolverTest.java b/log4j-layout-template-json-test/src/test/java/org/apache/logging/log4j/layout/template/json/resolver/StackTraceStringResolverTest.java index 430d6de646..dd3b371e10 100644 --- a/log4j-layout-template-json-test/src/test/java/org/apache/logging/log4j/layout/template/json/resolver/StackTraceStringResolverTest.java +++ b/log4j-layout-template-json-test/src/test/java/org/apache/logging/log4j/layout/template/json/resolver/StackTraceStringResolverTest.java @@ -16,6 +16,7 @@ */ package org.apache.logging.log4j.layout.template.json.resolver; +import static java.util.Collections.singletonList; import static org.apache.logging.log4j.layout.template.json.TestHelpers.CONFIGURATION; import static org.apache.logging.log4j.layout.template.json.TestHelpers.JAVA_BASE_PREFIX; import static org.apache.logging.log4j.layout.template.json.TestHelpers.asMap; @@ -40,6 +41,7 @@ import org.apache.logging.log4j.core.LogEvent; import org.apache.logging.log4j.core.impl.Log4jLogEvent; import org.apache.logging.log4j.layout.template.json.JsonTemplateLayout; import org.apache.logging.log4j.layout.template.json.JsonTemplateLayoutDefaults; +import org.apache.logging.log4j.layout.template.json.util.TruncatingBufferedPrintWriter; import org.apache.logging.log4j.util.Constants; import org.assertj.core.api.AbstractStringAssert; import org.junit.jupiter.api.Nested; @@ -593,6 +595,67 @@ class StackTraceStringResolverTest { private String matchingRegex(final String string) { return "[" + string.charAt(0) + "]" + Pattern.quote(string.substring(1)); } + + @Test + void should_not_fail_on_truncated_output_not_ending_with_newline() { + + // Try to find an exception whose truncated stack trace does not end with a newline + final int maxStringLength = 100; + final float maxByteCountPerChar = + JsonTemplateLayoutDefaults.getCharset().newEncoder().maxBytesPerChar(); + final int maxStringByteCount = + Math.toIntExact(Math.round(Math.ceil(maxByteCountPerChar * maxStringLength))); + final TruncatingBufferedPrintWriter writer = TruncatingBufferedPrintWriter.ofCapacity(maxStringByteCount); + Exception exception; + String message = "m"; + do { + exception = new Exception(message); + exception.printStackTrace(writer); + if (writer.truncated() && writer.buffer()[writer.length() - 1] != '\n') { + break; + } + writer.close(); + message += "m"; + } while (true); + + // Create the event template + final String eventTemplate = writeJson(asMap( + "ex", + asMap( + "$resolver", + "exception", + "field", + "stackTrace", + "stackTrace", + asMap( + "stringified", + asMap( + "truncation", + asMap( + "suffix", + TRUNCATION_SUFFIX, + "pointMatcherStrings", + singletonList("this string shouldn't match with anything"))))))); + + // Create the layout + final JsonTemplateLayout layout = JsonTemplateLayout.newBuilder() + .setConfiguration(CONFIGURATION) + .setEventTemplate(eventTemplate) + .setMaxStringLength(maxStringLength) + .setStackTraceEnabled(true) + .build(); + + // Create the log event + final LogEvent logEvent = + Log4jLogEvent.newBuilder().setThrown(exception).build(); + + // Check the serialized event + usingSerializedLogEventAccessor(layout, logEvent, accessor -> { + final int expectedStackTraceLength = maxStringLength + TRUNCATION_SUFFIX.length(); + final String stackTrace = accessor.getString("ex"); + assertThat(stackTrace).hasSizeLessThan(expectedStackTraceLength); + }); + } } @Test diff --git a/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/resolver/StackTraceStringResolver.java b/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/resolver/StackTraceStringResolver.java index ebd34a3a47..077bf3d359 100644 --- a/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/resolver/StackTraceStringResolver.java +++ b/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/resolver/StackTraceStringResolver.java @@ -251,13 +251,14 @@ final class StackTraceStringResolver implements StackTraceResolver { private static int findLineStartIndex(final CharSequence buffer, final int startIndex, final int endIndex) { char prevChar = '-'; - for (int i = startIndex; i <= endIndex; i++) { + int i = startIndex; + for (; i < endIndex; i++) { if (prevChar == '\n') { return i; } prevChar = buffer.charAt(i); } - return -1; + return prevChar == '\n' ? i : -1; } private static int findMatchingIndex( diff --git a/src/changelog/.2.x.x/3211_fix_JTL_StackTraceStringResolver.xml b/src/changelog/.2.x.x/3211_fix_JTL_StackTraceStringResolver.xml new file mode 100644 index 0000000000..e28bdbc207 --- /dev/null +++ b/src/changelog/.2.x.x/3211_fix_JTL_StackTraceStringResolver.xml @@ -0,0 +1,8 @@ +<?xml version="1.0" encoding="UTF-8"?> +<entry xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xmlns="https://logging.apache.org/xml/ns" + xsi:schemaLocation="https://logging.apache.org/xml/ns https://logging.apache.org/xml/ns/log4j-changelog-0.xsd" + type="fixed"> + <issue id="3211" link="https://github.com/apache/logging-log4j2/pull/3211"/> + <description format="asciidoc">Fix `ArrayIndexOutOfBoundsException` in JSON Template Layout truncated exception resolver</description> +</entry>
