This is an automated email from the ASF dual-hosted git repository. markt-asf pushed a commit to branch 9.0.x in repository https://gitbox.apache.org/repos/asf/tomcat.git
commit 2d240a37384b4b372c5a0490129c3156a545b6d4 Author: Mark Thomas <[email protected]> AuthorDate: Thu Nov 5 20:50:14 2026 +0000 Fix backport --- java/org/apache/jasper/compiler/SmapUtil.java | 46 +++++++++++++++++------ test/org/apache/jasper/compiler/TestSmapUtil.java | 7 ++-- 2 files changed, 38 insertions(+), 15 deletions(-) diff --git a/java/org/apache/jasper/compiler/SmapUtil.java b/java/org/apache/jasper/compiler/SmapUtil.java index 16fc20f319..8f216716d8 100644 --- a/java/org/apache/jasper/compiler/SmapUtil.java +++ b/java/org/apache/jasper/compiler/SmapUtil.java @@ -16,8 +16,8 @@ */ package org.apache.jasper.compiler; -import java.io.ByteArrayOutputStream; import java.io.BufferedInputStream; +import java.io.ByteArrayOutputStream; import java.io.DataInputStream; import java.io.EOFException; import java.io.File; @@ -31,7 +31,6 @@ import java.io.PrintWriter; import java.io.UnsupportedEncodingException; import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; -import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; import java.util.Map; @@ -459,6 +458,8 @@ public class SmapUtil { private static final int MAGIC = 0xCAFEBABE; + private static final int READ_CHUNK_SIZE = 8192; + private static final byte[] SMAP_HEADER_BYTES = SMAP_HEADER.getBytes(StandardCharsets.ISO_8859_1); private final DataInputStream in; @@ -506,10 +507,7 @@ public class SmapUtil { int nameIndex = in.readUnsignedShort(); int len = readLength(); if (sdeIndexes.contains(Integer.valueOf(nameIndex))) { - byte[] sde = in.readNBytes(len); - if (sde.length != len) { - throw new EOFException(); - } + byte[] sde = readBytes(len); if (isSmap(sde)) { smap = sde; } @@ -521,8 +519,16 @@ public class SmapUtil { } private static boolean isSmap(byte[] sde) { - return sde.length >= SMAP_HEADER_BYTES.length && - Arrays.equals(sde, 0, SMAP_HEADER_BYTES.length, SMAP_HEADER_BYTES, 0, SMAP_HEADER_BYTES.length); + if (sde.length < SMAP_HEADER_BYTES.length) { + return false; + } + // Arrays.equals() with ranges is not available in all supported Java versions + for (int i = 0; i < SMAP_HEADER_BYTES.length; i++) { + if (sde[i] != SMAP_HEADER_BYTES[i]) { + return false; + } + } + return true; } /* @@ -565,10 +571,7 @@ public class SmapUtil { case 1: // Utf8 int len = in.readUnsignedShort(); if (len == SDEInstaller.nameSDE.length()) { - byte[] utf8 = in.readNBytes(len); - if (utf8.length != len) { - throw new EOFException(); - } + byte[] utf8 = readBytes(len); if (SDEInstaller.nameSDE.equals(new String(utf8, StandardCharsets.UTF_8))) { sdeIndexes.add(Integer.valueOf(i)); } @@ -583,6 +586,25 @@ public class SmapUtil { return sdeIndexes; } + /* + * Reads exactly the requested number of bytes or throws an EOFException if the end of the stream is reached + * first. InputStream.readNBytes() is not used as it is not available in all supported Java versions. The length + * comes from the class file so the data is read in chunks rather than allocating an array of that size up + * front, which a corrupt length could make very large. + */ + private byte[] readBytes(int count) throws IOException { + byte[] chunk = new byte[Math.min(count, READ_CHUNK_SIZE)]; + ByteArrayOutputStream out = new ByteArrayOutputStream(chunk.length); + int remaining = count; + while (remaining > 0) { + int toRead = Math.min(remaining, chunk.length); + in.readFully(chunk, 0, toRead); + out.write(chunk, 0, toRead); + remaining -= toRead; + } + return out.toByteArray(); + } + /* * Skips exactly the requested number of bytes. InputStream.skipNBytes() is not used as it is not available in * all supported Java versions and InputStream.skip() may skip fewer bytes than requested. diff --git a/test/org/apache/jasper/compiler/TestSmapUtil.java b/test/org/apache/jasper/compiler/TestSmapUtil.java index 85d207e679..dddd716820 100644 --- a/test/org/apache/jasper/compiler/TestSmapUtil.java +++ b/test/org/apache/jasper/compiler/TestSmapUtil.java @@ -26,8 +26,8 @@ import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; import java.util.List; -import java.util.Map; import org.junit.After; import org.junit.Assert; @@ -185,7 +185,8 @@ public class TestSmapUtil extends TomcatBaseTest { @Test public void testLoadSmapNotAClassFile() throws Exception { File dir = createDir(); - Files.writeString(new File(dir, "Test.class").toPath(), "CAFEBABE junk\n" + SMAP, StandardCharsets.ISO_8859_1); + Files.write(new File(dir, "Test.class").toPath(), + ("CAFEBABE junk\n" + SMAP).getBytes(StandardCharsets.ISO_8859_1)); Assert.assertNull(SmapUtil.loadSmap("Test", loader(dir))); } @@ -215,7 +216,7 @@ public class TestSmapUtil extends TomcatBaseTest { stratum.setClassFileName(file.getAbsolutePath()); stratum.addFile("ERRORS.SMAP"); stratum.addLineData(1, "ERRORS.SMAP", 4, 120, 1); - SmapUtil.installSmap(Map.of("Test", stratum)); + SmapUtil.installSmap(Collections.singletonMap("Test", stratum)); SmapStratum loaded = SmapUtil.loadSmap("Test", loader(dir)); --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
