Uploaded image for project: 'Commons BCEL'
  1. Commons BCEL
  2. BCEL-159

LocalVariableGen.getLocalVariable() computes incorrect length

    Details

    • Type: Bug
    • Status: Closed
    • Priority: Blocker
    • Resolution: Fixed
    • Affects Version/s: 5.3
    • Fix Version/s: 6.0
    • Component/s: Main
    • Labels:
      None

      Description

      It seems that getLocalVariable computes incorrect length for the returning LocalVariable if its range is not the whole method. This is the original code:

      public LocalVariable getLocalVariable( ConstantPoolGen cp ) {
      int start_pc = start.getPosition();
      int length = end.getPosition() - start_pc;
      if (length > 0)

      { length += end.getInstruction().getLength(); }

      int name_index = cp.addUtf8(name);
      int signature_index = cp.addUtf8(type.getSignature());
      return new LocalVariable(start_pc, length, name_index, signature_index, index, cp.getConstantPool());
      }

      I think that the check "if (length > 0)" is a "workaround" for local variables whose end targets the last instruction. In this case, we must add the instruction length to recover the actual range for the local variable. However, we should not add the instruction's length if it is not the last instruction of the list because variable ranges are exclusive in the end_pc (note that the JVM spec used to say that the range is inclusive, but this was corrected in JVM5 - see http://java.sun.com/docs/books/jvms/second_edition/jvms-clarify.html or more specifically page 143 of http://java.sun.com/docs/books/jvms/second_edition/ClassFileFormat-Java5.pdf ).

      This error can be verified by parsing a method that has local variables whose range is not the whole method (like variables for exceptions in an exception handler), creating a MethodGen and then comparing the local variable tables. Something like this:

      ClassParser parser = new ClassParser(...);
      JavaClass clazz = parser.parse();
      Method m = clazz.getMethods()[...];
      ConstantPoolGen cpg = new ConstantPoolGen(clazz.getConstantPool());
      MethodGen mg = new MethodGen(m, clazz.getClassName(), cpg);
      System.out.println(mg.getLocalVariableTable(cpg));
      System.out.println("==");
      System.out.println(m.getLocalVariableTable());

      would produce some output which includes:

      LocalVariable(start_pc = 17, length = 7, index = 2:Exception e1)
      ...
      ==
      ...
      LocalVariable(start_pc = 17, length = 6, index = 2:Exception e1)

      Note that the length is greater than the original.

      If this is really a bug, I believe a fix is to use if (end.getNext() == null) instead (see the patch in attachment). I ran the whole test suite with this fix and it passes, but I am not sure what else it affects.

      Cheers,
      Thiago

        Attachments

          Activity

            People

            • Assignee:
              issues@commons.apache.org Apache Commons Developers
              Reporter:
              thiagobart@gmail.com Thiago
            • Votes:
              0 Vote for this issue
              Watchers:
              1 Start watching this issue

              Dates

              • Created:
                Updated:
                Resolved: