diff --git a/jode/ChangeLog b/jode/ChangeLog index d18559c..5704e6c 100644 --- a/jode/ChangeLog +++ b/jode/ChangeLog @@ -1,3 +1,21 @@ +2007-07-31 Jochen Hoenicke + + * jode/bytecode/ClassInfo.java.in: + (readAttribute): Never read in known attributes as unknown + attributes. This could happen before when class was first read with + known info and then again with all info. + * jode/bytecode/MethodInfo.java: (readAttribute): Likewise. + * jode/bytecode/FieldInfo.java: (readAttribute): Likewise. + * jode/bytecode/BytecodeInfo.java.in: (readAttribute): Likewise. + + * jode/obfuscator/ClassIdentifier.java: (doTransformation): Remove + all unknown attributes. They may contain references to + nonexisting constant pool entries. + + * jode/obfuscator/PackageIdentifier.java: (loadClass): Fix a + compile time bug in the last patch. + + 2005-09-13 Jochen Hoenicke Check for NullPointer in SyntheticAnalyzer. Based on diff --git a/jode/jode/bytecode/BytecodeInfo.java.in b/jode/jode/bytecode/BytecodeInfo.java.in index 06b5872..2608321 100644 --- a/jode/jode/bytecode/BytecodeInfo.java.in +++ b/jode/jode/bytecode/BytecodeInfo.java.in @@ -211,94 +211,98 @@ public class BytecodeInfo extends BinaryInfo implements Opcodes { protected void readAttribute(String name, int length, ConstantPool cp, DataInputStream input, int howMuch) throws IOException { - if ((howMuch & KNOWNATTRIBS) != 0 - && name.equals("LocalVariableTable")) { - if ((GlobalOptions.debuggingFlags & GlobalOptions.DEBUG_LVT) != 0) - GlobalOptions.err.println("LocalVariableTable of "+methodInfo); - int count = input.readUnsignedShort(); - if (length != 2 + count * 10) { + if (name.equals("LocalVariableTable")) { + if ((howMuch & KNOWNATTRIBS) != 0){ if ((GlobalOptions.debuggingFlags & GlobalOptions.DEBUG_LVT) != 0) - GlobalOptions.err.println("Illegal LVT length, ignoring it"); - return; - } - lvt = new LocalVariableInfo[count]; - for (int i=0; i < count; i++) { - lvt[i] = new LocalVariableInfo(); - int start = input.readUnsignedShort(); - int end = start + input.readUnsignedShort(); - int nameIndex = input.readUnsignedShort(); - int typeIndex = input.readUnsignedShort(); - int slot = input.readUnsignedShort(); - Instruction startInstr = - start >= 0 && start < instrs.length ? instrs[start] : null; - Instruction endInstr; - if (end >=0 && end < instrs.length) - endInstr = instrs[end] == null ? null - : instrs[end].getPrevByAddr(); - else { - endInstr = null; - for (int nr = instrs.length - 1; nr >= 0; nr--) { - if (instrs[nr] != null) { - if (instrs[nr].getNextAddr() == end) - endInstr = instrs[nr]; - break; + GlobalOptions.err.println("LocalVariableTable of "+methodInfo); + int count = input.readUnsignedShort(); + if (length != 2 + count * 10) { + if ((GlobalOptions.debuggingFlags & GlobalOptions.DEBUG_LVT) != 0) + GlobalOptions.err.println("Illegal LVT length, ignoring it"); + return; + } + lvt = new LocalVariableInfo[count]; + for (int i=0; i < count; i++) { + lvt[i] = new LocalVariableInfo(); + int start = input.readUnsignedShort(); + int end = start + input.readUnsignedShort(); + int nameIndex = input.readUnsignedShort(); + int typeIndex = input.readUnsignedShort(); + int slot = input.readUnsignedShort(); + Instruction startInstr = + start >= 0 && start < instrs.length ? instrs[start] : null; + Instruction endInstr; + if (end >=0 && end < instrs.length) + endInstr = instrs[end] == null ? null + : instrs[end].getPrevByAddr(); + else { + endInstr = null; + for (int nr = instrs.length - 1; nr >= 0; nr--) { + if (instrs[nr] != null) { + if (instrs[nr].getNextAddr() == end) + endInstr = instrs[nr]; + break; + } } } - } - - if (startInstr == null - || endInstr == null - || nameIndex == 0 || typeIndex == 0 - || slot >= maxLocals - || cp.getTag(nameIndex) != cp.UTF8 - || cp.getTag(typeIndex) != cp.UTF8) { - - // This is probably an evil lvt as created by HashJava - // simply ignore it. - if ((GlobalOptions.debuggingFlags - & GlobalOptions.DEBUG_LVT) != 0) - GlobalOptions.err.println + + if (startInstr == null + || endInstr == null + || nameIndex == 0 || typeIndex == 0 + || slot >= maxLocals + || cp.getTag(nameIndex) != cp.UTF8 + || cp.getTag(typeIndex) != cp.UTF8) { + + // This is probably an evil lvt as created by HashJava + // simply ignore it. + if ((GlobalOptions.debuggingFlags + & GlobalOptions.DEBUG_LVT) != 0) + GlobalOptions.err.println ("Illegal entry, ignoring LVT"); - lvt = null; - return; + lvt = null; + return; + } + lvt[i].start = startInstr; + lvt[i].end = endInstr; + lvt[i].name = cp.getUTF8(nameIndex); + lvt[i].type = cp.getUTF8(typeIndex); + lvt[i].slot = slot; + if ((GlobalOptions.debuggingFlags & GlobalOptions.DEBUG_LVT) != 0) + GlobalOptions.err.println("\t" + lvt[i].name + ": " + + lvt[i].type + +" range "+start+" - "+end + +" slot "+slot); } - lvt[i].start = startInstr; - lvt[i].end = endInstr; - lvt[i].name = cp.getUTF8(nameIndex); - lvt[i].type = cp.getUTF8(typeIndex); - lvt[i].slot = slot; - if ((GlobalOptions.debuggingFlags & GlobalOptions.DEBUG_LVT) != 0) - GlobalOptions.err.println("\t" + lvt[i].name + ": " - + lvt[i].type - +" range "+start+" - "+end - +" slot "+slot); - } - } else if ((howMuch & KNOWNATTRIBS) != 0 - && name.equals("LineNumberTable")) { - int count = input.readUnsignedShort(); - if (length != 2 + count * 4) { - GlobalOptions.err.println - ("Illegal LineNumberTable, ignoring it"); - return; - } - lnt = new LineNumber[count]; - for (int i = 0; i < count; i++) { - lnt[i] = new LineNumber(); - int start = input.readUnsignedShort(); - Instruction startInstr = instrs[start]; - if (startInstr == null) { + } else + input.readFully(new byte[length]); + } else if (name.equals("LineNumberTable")) { + if ((howMuch & KNOWNATTRIBS) != 0) { + int count = input.readUnsignedShort(); + if (length != 2 + count * 4) { GlobalOptions.err.println - ("Illegal entry, ignoring LineNumberTable table"); - lnt = null; + ("Illegal LineNumberTable, ignoring it"); return; } - lnt[i].start = startInstr; - lnt[i].linenr = input.readUnsignedShort(); - } + lnt = new LineNumber[count]; + for (int i = 0; i < count; i++) { + lnt[i] = new LineNumber(); + int start = input.readUnsignedShort(); + Instruction startInstr = instrs[start]; + if (startInstr == null) { + GlobalOptions.err.println + ("Illegal entry, ignoring LineNumberTable table"); + lnt = null; + return; + } + lnt[i].start = startInstr; + lnt[i].linenr = input.readUnsignedShort(); + } + } else + input.readFully(new byte[length]); } else super.readAttribute(name, length, cp, input, howMuch); } - + public void read(ConstantPool cp, DataInputStream input) throws IOException { maxStack = input.readUnsignedShort(); diff --git a/jode/jode/bytecode/ClassInfo.java.in b/jode/jode/bytecode/ClassInfo.java.in index 7db468f..8fd2a32 100644 --- a/jode/jode/bytecode/ClassInfo.java.in +++ b/jode/jode/bytecode/ClassInfo.java.in @@ -168,111 +168,116 @@ public class ClassInfo extends BinaryInfo { ConstantPool cp, DataInputStream input, int howMuch) throws IOException { - if ((howMuch & KNOWNATTRIBS) != 0 && name.equals("SourceFile")) { - if (length != 2) - throw new ClassFormatException("SourceFile attribute" - + " has wrong length"); - sourceFile = cp.getUTF8(input.readUnsignedShort()); - } else if ((howMuch & (OUTERCLASSES | INNERCLASSES)) != 0 - && name.equals("InnerClasses")) { - int count = input.readUnsignedShort(); - if (length != 2 + 8 * count) + if (name.equals("SourceFile")) { + if ((howMuch & KNOWNATTRIBS) != 0) { + if (length != 2) + throw new ClassFormatException("SourceFile attribute" + + " has wrong length"); + sourceFile = cp.getUTF8(input.readUnsignedShort()); + } else + input.readFully(new byte[length]); + } else if (name.equals("InnerClasses")) { + if ((howMuch & (OUTERCLASSES | INNERCLASSES)) != 0) { + int count = input.readUnsignedShort(); + if (length != 2 + 8 * count) throw new ClassFormatException ("InnerClasses attribute has wrong length"); - int innerCount = 0, outerCount = 0, extraCount = 0; - InnerClassInfo[] innerClassInfo = new InnerClassInfo[count]; - for (int i=0; i< count; i++) { - int innerIndex = input.readUnsignedShort(); - int outerIndex = input.readUnsignedShort(); - int nameIndex = input.readUnsignedShort(); - String inner = cp.getClassName(innerIndex); - String outer = - outerIndex != 0 ? cp.getClassName(outerIndex) : null; - String innername = - nameIndex != 0 ? cp.getUTF8(nameIndex) : null; - int access = input.readUnsignedShort(); - if (innername != null && innername.length() == 0) - innername = null; - - /* Some compilers give method scope classes a valid - * outer field, but we mustn't handle them as inner - * classes. The best way to distinguish this case - * is by the class name. + int innerCount = 0, outerCount = 0, extraCount = 0; + InnerClassInfo[] innerClassInfo = new InnerClassInfo[count]; + for (int i=0; i< count; i++) { + int innerIndex = input.readUnsignedShort(); + int outerIndex = input.readUnsignedShort(); + int nameIndex = input.readUnsignedShort(); + String inner = cp.getClassName(innerIndex); + String outer = + outerIndex != 0 ? cp.getClassName(outerIndex) : null; + String innername = + nameIndex != 0 ? cp.getUTF8(nameIndex) : null; + int access = input.readUnsignedShort(); + if (innername != null && innername.length() == 0) + innername = null; + + /* Some compilers give method scope classes a valid + * outer field, but we mustn't handle them as inner + * classes. The best way to distinguish this case + * is by the class name. + */ + if (outer != null && innername != null + && inner.length() > outer.length() + 2 + innername.length() + && inner.startsWith(outer+"$") + && inner.endsWith("$"+innername) + && Character.isDigit(inner.charAt(outer.length() + 1))) + outer = null; + + InnerClassInfo ici = new InnerClassInfo + (inner, outer, innername, access); + + if (outer != null && outer.equals(getName()) + && innername != null) + innerClassInfo[innerCount++] = ici; + else + innerClassInfo[count - (++extraCount)] = ici; + } + /* Now innerClasses are at the front of innerClassInfo array + * in correct order. The other InnerClassInfos are in reverse + * order in the rest of the innerClassInfo array. */ - if (outer != null && innername != null - && inner.length() > outer.length() + 2 + innername.length() - && inner.startsWith(outer+"$") - && inner.endsWith("$"+innername) - && Character.isDigit(inner.charAt(outer.length() + 1))) - outer = null; - - InnerClassInfo ici = new InnerClassInfo - (inner, outer, innername, access); - - if (outer != null && outer.equals(getName()) - && innername != null) - innerClassInfo[innerCount++] = ici; - else - innerClassInfo[count - (++extraCount)] = ici; - } - /* Now innerClasses are at the front of innerClassInfo array - * in correct order. The other InnerClassInfos are in reverse - * order in the rest of the innerClassInfo array. - */ - - /* We now count the outerClasses. The reverse order is the - * right thing for us. - */ - { - String lastOuterName = getName(); - for (int i = count - extraCount; - i < count && lastOuterName != null; i++) { - InnerClassInfo ici = innerClassInfo[i]; - if (ici.inner.equals(lastOuterName)) { - outerCount++; - extraCount--; - lastOuterName = ici.outer; + + /* We now count the outerClasses. The reverse order is the + * right thing for us. + */ + { + String lastOuterName = getName(); + for (int i = count - extraCount; + i < count && lastOuterName != null; i++) { + InnerClassInfo ici = innerClassInfo[i]; + if (ici.inner.equals(lastOuterName)) { + outerCount++; + extraCount--; + lastOuterName = ici.outer; + } } } - } - if (innerCount > 0) { - innerClasses = new InnerClassInfo[innerCount]; - System.arraycopy(innerClassInfo, 0, - innerClasses, 0, innerCount); - } else - innerClasses = null; - - if (outerCount > 0) { - outerClasses = new InnerClassInfo[outerCount]; - } else - outerClasses = null; - - if (extraCount > 0) { - extraClasses = new InnerClassInfo[extraCount]; - } else - extraClasses = null; - - /* The last part: We split between outer and extra classes. - * In this step we will also revert the order of the extra - * classes. - */ - { - int outerPtr = 0; - String lastOuterName = getName(); - for (int i = count - extraCount - outerCount; - i < count; i++) { - InnerClassInfo ici = innerClassInfo[i]; - - /* If we counted correctly there is no NullPointer - * or ArrayIndexOutOfBoundsException here - */ - if (ici.inner.equals(lastOuterName)) { - outerClasses[outerPtr++] = ici; - lastOuterName = ici.outer; - } else - extraClasses[--extraCount] = ici; + if (innerCount > 0) { + innerClasses = new InnerClassInfo[innerCount]; + System.arraycopy(innerClassInfo, 0, + innerClasses, 0, innerCount); + } else + innerClasses = null; + + if (outerCount > 0) { + outerClasses = new InnerClassInfo[outerCount]; + } else + outerClasses = null; + + if (extraCount > 0) { + extraClasses = new InnerClassInfo[extraCount]; + } else + extraClasses = null; + + /* The last part: We split between outer and extra classes. + * In this step we will also revert the order of the extra + * classes. + */ + { + int outerPtr = 0; + String lastOuterName = getName(); + for (int i = count - extraCount - outerCount; + i < count; i++) { + InnerClassInfo ici = innerClassInfo[i]; + + /* If we counted correctly there is no NullPointer + * or ArrayIndexOutOfBoundsException here + */ + if (ici.inner.equals(lastOuterName)) { + outerClasses[outerPtr++] = ici; + lastOuterName = ici.outer; + } else + extraClasses[--extraCount] = ici; + } } - } + } else + input.readFully(new byte[length]); } else if (name.equals("Deprecated")) { deprecatedFlag = true; if (length != 0) diff --git a/jode/jode/bytecode/FieldInfo.java b/jode/jode/bytecode/FieldInfo.java index 505fd04..50d453a 100644 --- a/jode/jode/bytecode/FieldInfo.java +++ b/jode/jode/bytecode/FieldInfo.java @@ -49,12 +49,15 @@ public class FieldInfo extends BinaryInfo { ConstantPool cp, DataInputStream input, int howMuch) throws IOException { - if ((howMuch & KNOWNATTRIBS) != 0 && name.equals("ConstantValue")) { - if (length != 2) - throw new ClassFormatException("ConstantValue attribute" - + " has wrong length"); - int index = input.readUnsignedShort(); - constant = cp.getConstant(index); + if (name.equals("ConstantValue")) { + if ((howMuch & KNOWNATTRIBS) != 0) { + if (length != 2) + throw new ClassFormatException("ConstantValue attribute" + + " has wrong length"); + int index = input.readUnsignedShort(); + constant = cp.getConstant(index); + } else + input.readFully(new byte[length]); } else if (name.equals("Synthetic")) { syntheticFlag = true; if (length != 0) diff --git a/jode/jode/bytecode/MethodInfo.java b/jode/jode/bytecode/MethodInfo.java index 7ae8c7e..c76384c 100644 --- a/jode/jode/bytecode/MethodInfo.java +++ b/jode/jode/bytecode/MethodInfo.java @@ -51,9 +51,12 @@ public class MethodInfo extends BinaryInfo { protected void readAttribute(String name, int length, ConstantPool cp, DataInputStream input, int howMuch) throws IOException { - if ((howMuch & KNOWNATTRIBS) != 0 && name.equals("Code")) { - bytecode = new BytecodeInfo(this); - bytecode.read(cp, input); + if (name.equals("Code")) { + if ((howMuch & KNOWNATTRIBS) != 0) { + bytecode = new BytecodeInfo(this); + bytecode.read(cp, input); + } else + input.readFully(new byte[length]); } else if (name.equals("Exceptions")) { int count = input.readUnsignedShort(); exceptions = new String[count]; diff --git a/jode/jode/obfuscator/ClassIdentifier.java.in b/jode/jode/obfuscator/ClassIdentifier.java.in index 5b60366..4eefa51 100644 --- a/jode/jode/obfuscator/ClassIdentifier.java.in +++ b/jode/jode/obfuscator/ClassIdentifier.java.in @@ -663,6 +663,10 @@ public class ClassIdentifier extends Identifier { } } + /* Drop unknown attributes. + * They may be broken now anyway due to renaming. + */ + info.dropInfo(info.UNKNOWN_ATTRIBUTES); info.setFields((FieldInfo[]) newFields.toArray (new FieldInfo[newFields.size()])); info.setMethods((MethodInfo[]) newMethods.toArray diff --git a/jode/jode/obfuscator/PackageIdentifier.java.in b/jode/jode/obfuscator/PackageIdentifier.java.in index 4dac970..2509be6 100644 --- a/jode/jode/obfuscator/PackageIdentifier.java.in +++ b/jode/jode/obfuscator/PackageIdentifier.java.in @@ -102,7 +102,7 @@ public class PackageIdentifier extends Identifier { loadedClasses.put(subclazz, ident); swappedClasses = null; bundle.addClassIdentifier(ident); - ((ClassIdentifier) ident).initClass(); + ident.initClass(); } } // Everything is loaded, we don't need to load on demand anymore. @@ -131,7 +131,7 @@ public class PackageIdentifier extends Identifier { public ClassIdentifier loadClass(String name) { int index = name.indexOf('.'); if (index == -1) { - ClassIdentifier ident = (Identifier) loadedClasses.get(name); + ClassIdentifier ident = (ClassIdentifier) loadedClasses.get(name); if (ident == null) { String subFull = (fullName.length() > 0) ? fullName + "."+ name : name; @@ -156,7 +156,7 @@ public class PackageIdentifier extends Identifier { loadedClasses.put(name, ident); swappedClasses = null; bundle.addClassIdentifier(ident); - ((ClassIdentifier) ident).initClass(); + ident.initClass(); } } return ident;