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);
+    }
+}

Reply via email to