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 b1a8992e Fix remaining missing StringRepresentation visitors
b1a8992e is described below

commit b1a8992eb5dd2ce91feed1f55539701e9d101c36
Author: Gary Gregory <[email protected]>
AuthorDate: Sat Nov 7 07:57:18 2026 -0500

    Fix remaining missing StringRepresentation visitors
    
    Add handlers for NestHost, MethodParameter, and StackMapType to prevent
    internal errors when rendering these nodes in verifier diagnostics.
    
    Add regression tests for successful rendering, malformed-data fallback,
    all stack-map type tags, and verification of a nest member.
---
 src/changes/changes.xml                            |  3 +
 .../verifier/statics/StringRepresentation.java     | 36 ++++++++++
 .../verifier/statics/StringRepresentationTest.java | 79 +++++++++++++++++++++-
 3 files changed, 117 insertions(+), 1 deletion(-)

diff --git a/src/changes/changes.xml b/src/changes/changes.xml
index 03366817..210cf5fe 100644
--- a/src/changes/changes.xml
+++ b/src/changes/changes.xml
@@ -70,6 +70,9 @@ The <action> type attribute can be add,update,fix,remove.
       <action                  type="fix" dev="ggregory" due-to="Gary 
Gregory">Clean up comments for spelling, grammar, and readability.</action>
       <action issue="BCEL-341" type="fix" dev="ggregory" due-to="Gary Gregory, 
Hippo">Support explicit parsing and generation of compact Code headers in class 
file versions 45.0 through 45.2 (#58).</action>
       <action                  type="fix" dev="ggregory" due-to="Gary Gregory, 
simpleqt">Fix module descriptor rendering in StringRepresentation 
(#543).</action>
+      <action                  type="fix" dev="ggregory" due-to="Gary 
Gregory">Fix NestHost rendering in StringRepresentation to prevent internal 
errors when verifying nest members.</action>
+      <action                  type="fix" dev="ggregory" due-to="Gary 
Gregory">Fix MethodParameter rendering in StringRepresentation.</action>
+      <action                  type="fix" dev="ggregory" due-to="Gary 
Gregory">Fix StackMapType rendering in StringRepresentation.</action>
       <!-- ADD -->
       <action                  type="add" dev="ggregory" due-to="Gary 
Gregory">Add and use ClassFormatException.ClassFormatException(String, 
Object...).</action>
       <action                  type="add" dev="ggregory" due-to="Nicolas 
Baumann, Gary Gregory">Add support for the RuntimeVisibleTypeAnnotations and 
RuntimeInvisibleTypeAnnotations attributes.</action>
diff --git 
a/src/main/java/org/apache/bcel/verifier/statics/StringRepresentation.java 
b/src/main/java/org/apache/bcel/verifier/statics/StringRepresentation.java
index f2296443..03b13c21 100644
--- a/src/main/java/org/apache/bcel/verifier/statics/StringRepresentation.java
+++ b/src/main/java/org/apache/bcel/verifier/statics/StringRepresentation.java
@@ -56,6 +56,7 @@ import org.apache.bcel.classfile.LocalVariable;
 import org.apache.bcel.classfile.LocalVariableTable;
 import org.apache.bcel.classfile.LocalVariableTypeTable;
 import org.apache.bcel.classfile.Method;
+import org.apache.bcel.classfile.MethodParameter;
 import org.apache.bcel.classfile.MethodParameters;
 import org.apache.bcel.classfile.Module;
 import org.apache.bcel.classfile.ModuleExports;
@@ -64,6 +65,7 @@ import org.apache.bcel.classfile.ModuleOpens;
 import org.apache.bcel.classfile.ModulePackages;
 import org.apache.bcel.classfile.ModuleProvides;
 import org.apache.bcel.classfile.ModuleRequires;
+import org.apache.bcel.classfile.NestHost;
 import org.apache.bcel.classfile.NestMembers;
 import org.apache.bcel.classfile.Node;
 import org.apache.bcel.classfile.ParameterAnnotationEntry;
@@ -75,6 +77,7 @@ import org.apache.bcel.classfile.Signature;
 import org.apache.bcel.classfile.SourceFile;
 import org.apache.bcel.classfile.StackMap;
 import org.apache.bcel.classfile.StackMapEntry;
+import org.apache.bcel.classfile.StackMapType;
 import org.apache.bcel.classfile.Synthetic;
 import org.apache.bcel.classfile.TypeAnnotations;
 import org.apache.bcel.classfile.Unknown;
@@ -378,6 +381,17 @@ public class StringRepresentation extends 
org.apache.bcel.classfile.EmptyVisitor
         tostring = toString(obj);
     }
 
+    /**
+     * Visits a method parameter.
+     *
+     * @param obj The node to represent.
+     * @since 6.14.0
+     */
+    @Override
+    public void visitMethodParameter(final MethodParameter obj) {
+        tostring = toString(obj);
+    }
+
     /**
      * @since 6.0
      */
@@ -456,6 +470,17 @@ public class StringRepresentation extends 
org.apache.bcel.classfile.EmptyVisitor
         tostring = toString(obj);
     }
 
+    /**
+     * Visits the NestHost attribute.
+     *
+     * @param obj The node to represent.
+     * @since 6.14.0
+     */
+    @Override
+    public void visitNestHost(final NestHost obj) {
+        tostring = toString(obj);
+    }
+
     /**
      * @since 6.4.0
      */
@@ -523,6 +548,17 @@ public class StringRepresentation extends 
org.apache.bcel.classfile.EmptyVisitor
         tostring = toString(obj);
     }
 
+    /**
+     * Visits a stack map verification type.
+     *
+     * @param obj The node to represent.
+     * @since 6.14.0
+     */
+    @Override
+    public void visitStackMapType(final StackMapType obj) {
+        tostring = toString(obj);
+    }
+
     @Override
     public void visitSynthetic(final Synthetic obj) {
         tostring = toString(obj);
diff --git 
a/src/test/java/org/apache/bcel/verifier/statics/StringRepresentationTest.java 
b/src/test/java/org/apache/bcel/verifier/statics/StringRepresentationTest.java
index 4d43b2d4..d708c836 100644
--- 
a/src/test/java/org/apache/bcel/verifier/statics/StringRepresentationTest.java
+++ 
b/src/test/java/org/apache/bcel/verifier/statics/StringRepresentationTest.java
@@ -47,10 +47,14 @@ import org.apache.bcel.classfile.ClassParser;
 import org.apache.bcel.classfile.Constant;
 import org.apache.bcel.classfile.ConstantPool;
 import org.apache.bcel.classfile.JavaClass;
+import org.apache.bcel.classfile.MethodParameter;
 import org.apache.bcel.classfile.Module;
 import org.apache.bcel.classfile.ModuleMainClass;
 import org.apache.bcel.classfile.ModulePackages;
+import org.apache.bcel.classfile.NestHost;
 import org.apache.bcel.classfile.Node;
+import org.apache.bcel.classfile.StackMapType;
+import org.apache.bcel.generic.ClassGen;
 import org.apache.bcel.generic.ConstantPoolGen;
 import org.apache.bcel.verifier.VerificationResult;
 import org.apache.bcel.verifier.Verifier;
@@ -59,7 +63,7 @@ import org.junit.jupiter.api.AfterEach;
 import org.junit.jupiter.api.Test;
 
 /**
- * Tests {@link StringRepresentation} with the attributes of a module 
descriptor.
+ * Tests {@link StringRepresentation} with class file attributes and their 
entries.
  * <p>
  * A module descriptor contains attributes and entries that a class file 
verifier reports when it finds something it does not know, so
  * {@link StringRepresentation} must be able to represent them instead of 
failing with an internal error.
@@ -111,6 +115,30 @@ class StringRepresentationTest {
         assertEquals("<<ModulePackages>>", new 
StringRepresentation(modulePackages).toString());
     }
 
+    @Test
+    void testMalformedNestHost() {
+        final ConstantPoolGen pool = new ConstantPoolGen();
+        final int nameIndex = pool.addUtf8("NestHost");
+        final NestHost nestHost = new NestHost(nameIndex, 2, nameIndex, 
pool.getConstantPool());
+        assertThrows(ClassFormatException.class, nestHost::toString);
+        assertEquals("<<NestHost>>", new 
StringRepresentation(nestHost).toString());
+    }
+
+    @Test
+    void testMalformedStackMapType() {
+        final ConstantPoolGen pool = new ConstantPoolGen();
+        final int utf8Index = pool.addUtf8("NotAClassConstant");
+        final StackMapType type = new StackMapType(Const.ITEM_Object, 
utf8Index, pool.getConstantPool());
+        assertThrows(ClassFormatException.class, type::toString);
+        assertEquals("<<StackMapType>>", new 
StringRepresentation(type).toString());
+    }
+
+    @Test
+    void testMethodParameter() {
+        final MethodParameter parameter = new MethodParameter();
+        assertEquals(parameter.toString(), new 
StringRepresentation(parameter).toString());
+    }
+
     @Test
     void testModuleAttribute() throws IOException {
         final Attribute module = findAttribute(parseModuleInfo(), "Module");
@@ -169,6 +197,16 @@ class StringRepresentationTest {
         }
     }
 
+    @Test
+    void testNestHost() {
+        final ConstantPoolGen pool = new ConstantPoolGen();
+        final int nameIndex = pool.addUtf8("NestHost");
+        final int hostIndex = pool.addClass("example.Host");
+        final NestHost nestHost = new NestHost(nameIndex, 2, hostIndex, 
pool.getConstantPool());
+        assertEquals("NestHost: example.Host", new 
StringRepresentation(nestHost).toString());
+        assertEquals(nestHost.toString(), new 
StringRepresentation(nestHost).toString());
+    }
+
     @Test
     void testOtherModuleDescriptorAttributes() throws IOException {
         final JavaClass moduleInfo = parseModuleInfo();
@@ -185,6 +223,16 @@ class StringRepresentationTest {
         }
     }
 
+    @Test
+    void testStackMapTypes() {
+        final ConstantPoolGen pool = new ConstantPoolGen();
+        final int classIndex = pool.addClass("example.Value");
+        for (byte tag = Const.ITEM_Bogus; tag <= Const.ITEM_NewObject; tag++) {
+            final StackMapType type = new StackMapType(tag, tag == 
Const.ITEM_Object ? classIndex : 0, pool.getConstantPool());
+            assertEquals(type.toString(), new 
StringRepresentation(type).toString(), "Verification type tag " + tag);
+        }
+    }
+
     @Test
     void testVerifierOnAModuleDescriptor() throws IOException, 
ClassNotFoundException {
         final JavaClass moduleInfo = parseModuleInfo();
@@ -205,4 +253,33 @@ class StringRepresentationTest {
             }
         }
     }
+
+    @Test
+    void testVerifierOnNestMember() throws IOException, ClassNotFoundException 
{
+        final ClassGen generator = new ClassGen("example.Host$Member", 
"java.lang.Object", "Host.java",
+                Const.ACC_PUBLIC | Const.ACC_SUPER, new String[0]);
+        generator.setMajor(Const.MAJOR_11);
+        final ConstantPoolGen pool = generator.getConstantPool();
+        final int nameIndex = pool.addUtf8("NestHost");
+        final int hostIndex = pool.addClass("example.Host");
+        generator.addAttribute(new NestHost(nameIndex, 2, hostIndex, 
pool.getConstantPool()));
+        // BCEL parses the generated Java 11 class; the JVM never loads it, 
including on Java 8.
+        final JavaClass member;
+        try (InputStream input = new 
ByteArrayInputStream(generator.getJavaClass().getBytes())) {
+            member = new ClassParser(input, "Host$Member.class").parse();
+        }
+        final JavaClass previous = Repository.addClass(member);
+        try {
+            final Verifier verifier = 
VerifierFactory.getVerifier(member.getClassName());
+            verifier.flush();
+            assertEquals(VerificationResult.VR_OK, 
assertDoesNotThrow(verifier::doPass2));
+            assertTrue(Arrays.stream(verifier.getMessages()).anyMatch(message 
-> message.contains("NestHost: example.Host")
+                    && message.contains("is unknown and will therefore be 
ignored")));
+        } finally {
+            Repository.removeClass(member);
+            if (previous != null) {
+                Repository.addClass(previous);
+            }
+        }
+    }
 }

Reply via email to