8064516: BCEL still corrupts generic methods if bytecode offsets are modified
authordbuck
Mon, 10 Nov 2014 16:09:38 -0800
changeset 27537 77d9ab3c1028
parent 27536 533660d72131
child 27538 bd7c7463b5fc
8064516: BCEL still corrupts generic methods if bytecode offsets are modified Summary: Added comprehensive support for LocalVariableTypeTable to MethodGen. Reviewed-by: joehw
jaxp/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/DescendingVisitor.java
jaxp/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/MethodGen.java
--- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/DescendingVisitor.java	Fri Nov 07 13:18:58 2014 -0800
+++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/DescendingVisitor.java	Mon Nov 10 16:09:38 2014 -0800
@@ -213,6 +213,10 @@
   public void visitLocalVariableTypeTable(LocalVariableTypeTable obj) {
     stack.push(obj);
     obj.accept(visitor);
+
+    LocalVariable[] vars = obj.getLocalVariableTypeTable();
+    for(int i=0; i < vars.length; i++)
+      vars[i].accept(this);
     stack.pop();
   }
 
--- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/MethodGen.java	Fri Nov 07 13:18:58 2014 -0800
+++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/MethodGen.java	Mon Nov 10 16:09:38 2014 -0800
@@ -87,6 +87,7 @@
   private boolean         strip_attributes;
 
   private ArrayList       variable_vec    = new ArrayList();
+  private ArrayList       type_vec        = new ArrayList();
   private ArrayList       line_number_vec = new ArrayList();
   private ArrayList       exception_vec   = new ArrayList();
   private ArrayList       throws_vec      = new ArrayList();
@@ -259,11 +260,10 @@
                                l.getIndex(), start, end);
             }
           } else if (a instanceof LocalVariableTypeTable) {
-             LocalVariable[] oldLV = ((LocalVariableTypeTable) a).getLocalVariableTypeTable();
-             int lvLength = oldLV.length;
-             LocalVariable[] newLV = new LocalVariable[lvLength];
-             for (int k = 0; k < lvLength; k++) {
-                 LocalVariable l = oldLV[k];
+             LocalVariable[] lv = ((LocalVariableTypeTable) a).getLocalVariableTypeTable();
+             removeLocalVariableTypes();
+             for (int k = 0; k < lv.length; k++) {
+                 LocalVariable l = lv[k];
                  InstructionHandle start = il.findHandle(l.getStartPC());
                  InstructionHandle end = il.findHandle(l.getStartPC() + l.getLength());
                  // Repair malformed handles
@@ -273,16 +273,9 @@
                  if (null == end) {
                      end = il.getEnd();
                  }
-                 LocalVariable newVar = new LocalVariable(l);
-                 int startPosition = start.getPosition();
-                 newVar.setStartPC(startPosition);
-                 newVar.setLength(end.getPosition() - startPosition);
-                 newLV[k] = newVar;
+                 addLocalVariableType(l.getName(), Type.getType(l.getSignature()), l
+                         .getIndex(), start, end);
               }
-              LocalVariableTypeTable newLVTT = new LocalVariableTypeTable(
-                      (LocalVariableTypeTable)a);
-              newLVTT.setLocalVariableTable(newLV);
-              addCodeAttribute(newLVTT);
           } else
             addCodeAttribute(a);
         }
@@ -414,6 +407,31 @@
     return lg;
   }
 
+  /*
+   * If the range of the variable has not been set yet, it will be set to be
+   * val id from the start to the end of the instruction list.
+   *
+   * @return array of declared local variable types sorted by index
+   */
+  private LocalVariableGen[] getLocalVariableTypes() {
+    int                size = type_vec.size();
+    LocalVariableGen[] lg   = new LocalVariableGen[size];
+    type_vec.toArray(lg);
+
+    for(int i=0; i < size; i++) {
+      if(lg[i].getStart() == null)
+        lg[i].setStart(il.getStart());
+
+      if(lg[i].getEnd() == null)
+        lg[i].setEnd(il.getEnd());
+    }
+
+    if(size > 1)
+      sort(lg, 0, size - 1);
+
+    return lg;
+  }
+
   /**
    * @return `LocalVariableTable' attribute of all the local variables of this method.
    */
@@ -430,6 +448,68 @@
   }
 
   /**
+   * @return `LocalVariableTypeTable' attribute of all the local variable
+   * types of this method.
+   */
+  public LocalVariableTypeTable getLocalVariableTypeTable(ConstantPoolGen cp) {
+    LocalVariableGen[] lg   = getLocalVariableTypes();
+    int                size = lg.length;
+    LocalVariable[]    lv   = new LocalVariable[size];
+
+    for(int i=0; i < size; i++)
+      lv[i] = lg[i].getLocalVariable(cp);
+
+    return new LocalVariableTypeTable(cp.addUtf8("LocalVariableTypeTable"),
+                                  2 + lv.length * 10, lv, cp.getConstantPool());
+  }
+
+  /**
+   * Adds a local variable type to this method.
+   *
+   * @param name variable name
+   * @param type variable type
+   * @param slot the index of the local variable, if type is long or double, the next available
+   * index is slot+2
+   * @param start from where the variable is valid
+   * @param end until where the variable is valid
+   * @return new local variable object
+   * @see LocalVariable
+   */
+  private LocalVariableGen addLocalVariableType(String name, Type type, int slot,
+                                           InstructionHandle start,
+                                           InstructionHandle end) {
+    byte t = type.getType();
+
+    if(t != Constants.T_ADDRESS) {
+      int  add = type.getSize();
+
+      if(slot + add > max_locals)
+        max_locals = slot + add;
+
+      LocalVariableGen l = new LocalVariableGen(slot, name, type, start, end);
+      int i;
+
+      if((i = type_vec.indexOf(l)) >= 0) // Overwrite if necessary
+        type_vec.set(i, l);
+      else
+        type_vec.add(l);
+
+      return l;
+    } else {
+      throw new IllegalArgumentException("Can not use " + type +
+                                         " as type for local variable");
+
+    }
+  }
+
+  /**
+   * Remove all local variable types.
+   */
+  private void removeLocalVariableTypes() {
+    type_vec.clear();
+  }
+
+  /**
    * Give an instruction a line number corresponding to the source code line.
    *
    * @param ih instruction to tag
@@ -645,12 +725,17 @@
 
     LineNumberTable    lnt = null;
     LocalVariableTable lvt = null;
+    LocalVariableTypeTable lvtt = null;
 
-    /* Create LocalVariableTable and LineNumberTable attributes (for debuggers, e.g.)
+    /* Create LocalVariableTable, LocalvariableTypeTable, and LineNumberTable
+     * attributes (for debuggers, e.g.)
      */
     if((variable_vec.size() > 0) && !strip_attributes)
       addCodeAttribute(lvt = getLocalVariableTable(cp));
 
+    if((type_vec.size() > 0) && !strip_attributes)
+      addCodeAttribute(lvtt = getLocalVariableTypeTable(cp));
+
     if((line_number_vec.size() > 0) && !strip_attributes)
       addCodeAttribute(lnt = getLineNumberTable(cp));
 
@@ -699,6 +784,7 @@
 
     // Undo effects of adding attributes
     if(lvt != null)  removeCodeAttribute(lvt);
+    if(lvtt != null) removeCodeAttribute(lvtt);
     if(lnt != null)  removeCodeAttribute(lnt);
     if(code != null) removeAttribute(code);
     if(et != null)   removeAttribute(et);