This is an automated email from the ASF dual-hosted git repository.
garydgregory pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/commons-bcel.git
The following commit(s) were added to refs/heads/master by this push:
new 296a4dd3 Read unsigned bytecode operands in CodeHTML disassembler
(#511)
296a4dd3 is described below
commit 296a4dd35e3bdb936e98867d1ae4fc7b3ae5d71e
Author: Dexter.k <[email protected]>
AuthorDate: Thu Jul 2 21:13:31 2026 +0000
Read unsigned bytecode operands in CodeHTML disassembler (#511)
---
src/main/java/org/apache/bcel/util/CodeHTML.java | 18 +++---
.../apache/bcel/util/CodeHTMLNarrowingTest.java | 71 ++++++++++++++++++++++
2 files changed, 80 insertions(+), 9 deletions(-)
diff --git a/src/main/java/org/apache/bcel/util/CodeHTML.java
b/src/main/java/org/apache/bcel/util/CodeHTML.java
index 53ffb3c9..bb7b09b7 100644
--- a/src/main/java/org/apache/bcel/util/CodeHTML.java
+++ b/src/main/java/org/apache/bcel/util/CodeHTML.java
@@ -195,7 +195,7 @@ final class CodeHTML {
case Const.LSTORE:
case Const.RET:
if (wide) {
- vindex = bytes.readShort();
+ vindex = bytes.readUnsignedShort();
wide = false; // Clear flag
} else {
vindex = bytes.readUnsignedByte();
@@ -223,7 +223,7 @@ final class CodeHTML {
case Const.GETSTATIC:
case Const.PUTFIELD:
case Const.PUTSTATIC:
- index = bytes.readShort();
+ index = bytes.readUnsignedShort();
final ConstantFieldref c1 = constantPool.getConstant(index,
Const.CONSTANT_Fieldref, ConstantFieldref.class);
classIndex = c1.getClassIndex();
name = constantPool.getConstantString(classIndex,
Const.CONSTANT_Class);
@@ -243,7 +243,7 @@ final class CodeHTML {
case Const.CHECKCAST:
case Const.INSTANCEOF:
case Const.NEW:
- index = bytes.readShort();
+ index = bytes.readUnsignedShort();
buf.append(constantHtml.referenceConstant(index));
break;
/*
@@ -254,7 +254,7 @@ final class CodeHTML {
case Const.INVOKEVIRTUAL:
case Const.INVOKEINTERFACE:
case Const.INVOKEDYNAMIC:
- final int mIndex = bytes.readShort();
+ final int mIndex = bytes.readUnsignedShort();
final String str;
if (opcode == Const.INVOKEINTERFACE) { // Special treatment needed
bytes.readUnsignedByte(); // Redundant
@@ -303,7 +303,7 @@ final class CodeHTML {
*/
case Const.LDC_W:
case Const.LDC2_W:
- index = bytes.readShort();
+ index = bytes.readUnsignedShort();
buf.append("<A
HREF=\"").append(className).append("_cp.html#cp").append(index).append("\"
TARGET=\"ConstantPool\">")
.append(Class2HTML.toHTML(constantPool.constantToString(index,
constantPool.getConstant(index).getTag()))).append("</a>");
break;
@@ -316,15 +316,15 @@ final class CodeHTML {
* Array of references.
*/
case Const.ANEWARRAY:
- index = bytes.readShort();
+ index = bytes.readUnsignedShort();
buf.append(constantHtml.referenceConstant(index));
break;
/*
* Multidimensional array of references.
*/
case Const.MULTIANEWARRAY:
- index = bytes.readShort();
- final int dimensions = bytes.readByte();
+ index = bytes.readUnsignedShort();
+ final int dimensions = bytes.readUnsignedByte();
buf.append(constantHtml.referenceConstant(index)).append(":").append(dimensions).append("-dimensional");
break;
/*
@@ -332,7 +332,7 @@ final class CodeHTML {
*/
case Const.IINC:
if (wide) {
- vindex = bytes.readShort();
+ vindex = bytes.readUnsignedShort();
constant = bytes.readShort();
wide = false;
} else {
diff --git a/src/test/java/org/apache/bcel/util/CodeHTMLNarrowingTest.java
b/src/test/java/org/apache/bcel/util/CodeHTMLNarrowingTest.java
new file mode 100644
index 00000000..73ffcf22
--- /dev/null
+++ b/src/test/java/org/apache/bcel/util/CodeHTMLNarrowingTest.java
@@ -0,0 +1,71 @@
+/*
+ * 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
+ *
+ * https://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.
+ */
+
+package org.apache.bcel.util;
+
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import java.io.File;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+
+import org.apache.bcel.Const;
+import org.apache.bcel.classfile.JavaClass;
+import org.apache.bcel.generic.ClassGen;
+import org.apache.bcel.generic.ConstantPoolGen;
+import org.apache.bcel.generic.ILOAD;
+import org.apache.bcel.generic.InstructionFactory;
+import org.apache.bcel.generic.InstructionList;
+import org.apache.bcel.generic.MethodGen;
+import org.apache.bcel.generic.Type;
+import org.junit.jupiter.api.Test;
+
+class CodeHTMLNarrowingTest {
+
+ /**
+ * A wide local-variable index is a u2 in the byte code; disassembling a
class whose index is >= 0x8000 must render the
+ * real slot number, not a sign-extended negative. The reference
disassembler {@code Utility.codeToString} reads it via
+ * {@code readUnsignedShort}.
+ */
+ @Test
+ void testWideLocalVariableIndexIsUnsigned() throws Exception {
+ final int index = 40000; // > 0x7FFF so a signed read wraps negative
+ final ClassGen cg = new ClassGen("Wide", "java.lang.Object",
"Wide.java", Const.ACC_PUBLIC, null);
+ final ConstantPoolGen cp = cg.getConstantPool();
+ final InstructionList il = new InstructionList();
+ il.append(new ILOAD(index)); // emitted as WIDE + iload + u2 index
+ il.append(InstructionFactory.createReturn(Type.INT));
+ final MethodGen mg = new MethodGen(Const.ACC_PUBLIC |
Const.ACC_STATIC, Type.INT, Type.NO_ARGS, null, "m", "Wide", il, cp);
+ mg.setMaxStack(1);
+ mg.setMaxLocals(index + 1);
+ cg.addMethod(mg.getMethod());
+ final JavaClass jc = cg.getJavaClass();
+
+ final File outputDir = new File("target/test-output/html-narrowing");
+ if (!outputDir.mkdirs()) {
+ assertTrue(outputDir.isDirectory());
+ }
+ new Class2HTML(jc, outputDir.getAbsolutePath() + File.separator);
+
+ final String code = new String(Files.readAllBytes(new File(outputDir,
"Wide_code.html").toPath()), StandardCharsets.UTF_8);
+ assertTrue(code.contains("%" + index), "expected the wide index
rendered as " + index);
+ assertFalse(code.contains("%" + (short) index), "wide index was
sign-extended to " + (short) index);
+ }
+}