📄 classclassfornamereferenceinitializer.java
字号:
/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2007 Eric Lafortune (eric@graphics.cornell.edu) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free * Software Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */package proguard.classfile.util;import proguard.classfile.*;import proguard.classfile.attribute.CodeAttribute;import proguard.classfile.constant.*;import proguard.classfile.instruction.*;import proguard.classfile.instruction.visitor.InstructionVisitor;import proguard.classfile.constant.visitor.ConstantVisitor;import proguard.util.ClassNameListMatcher;/** * This InstructionVisitor initializes any special <code>Class.forName</code> or * <code>.class</code> references of all classes it visits. More specifically, * it fills out the references of String constant pool entries that refer to a * class in the program class pool or in the library class pool. * <p> * It optionally prints notes if on usage of * <code>(SomeClass)Class.forName(variable).newInstance()</code>. * <p> * The class hierarchy must be initialized before using this visitor. * * @see ClassReferenceInitializer * * @author Eric Lafortune */public class ClassClassForNameReferenceInitializerextends SimplifiedVisitorimplements InstructionVisitor, ConstantVisitor{ private ClassPool programClassPool; private ClassPool libraryClassPool; private WarningPrinter notePrinter; private ClassNameListMatcher noteExceptionMatcher; // Fields to remember the previous StringConstant and MethodRefConstant objects // while visiting all instructions (to find Class.forName, class$, and // Class.newInstance invocations, and possible class casts afterwards). private int ldcStringConstantIndex = -1; private int invokestaticMethodRefConstantIndex = -1; private int invokevirtualMethodRefConstantIndex = -1; private ClassForNameChecker classForNameChecker = new ClassForNameChecker(); private ClassNewInstanceChecker classNewInstanceChecker = new ClassNewInstanceChecker(); /** * Creates a new ClassClassForNameReferenceInitializer that optionally * prints notes, with optional class specifications for which never to * print notes. */ public ClassClassForNameReferenceInitializer(ClassPool programClassPool, ClassPool libraryClassPool, WarningPrinter notePrinter, ClassNameListMatcher noteExceptionMatcher) { this.programClassPool = programClassPool; this.libraryClassPool = libraryClassPool; this.notePrinter = notePrinter; this.noteExceptionMatcher = noteExceptionMatcher; } // Implementations for InstructionVisitor. public void visitSimpleInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, SimpleInstruction simpleInstruction) { // Nothing interesting; just forget any stored indices. clearConstantPoolIndices(); } public void visitBranchInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, BranchInstruction branchInstruction) { // Nothing interesting; just forget any stored indices. clearConstantPoolIndices(); } public void visitTableSwitchInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, TableSwitchInstruction tableSwitchInstruction) { // Nothing interesting; just forget any stored indices. clearConstantPoolIndices(); } public void visitLookUpSwitchInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, LookUpSwitchInstruction lookUpSwitchInstruction) { // Nothing interesting; just forget any stored indices. clearConstantPoolIndices(); } public void visitVariableInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, VariableInstruction variableInstruction) { // Just ignore generic instructions and reset the constant pool indices. switch (variableInstruction.opcode) { case InstructionConstants.OP_ICONST_0: case InstructionConstants.OP_ICONST_1: // Still remember any loaded string; this instruction may be // setting up the second argument for class$(String, boolean). break; default: ldcStringConstantIndex = -1; break; } invokestaticMethodRefConstantIndex = -1; invokevirtualMethodRefConstantIndex = -1; } public void visitConstantInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, ConstantInstruction constantInstruction) { int currentConstantIndex = constantInstruction.constantIndex; switch (constantInstruction.opcode) { case InstructionConstants.OP_LDC: case InstructionConstants.OP_LDC_W: // Are we loading a constant String? int currentTag = clazz.getTag(currentConstantIndex); if (currentTag == ClassConstants.CONSTANT_String) { // Remember it; it might be the argument of // Class.forName(String), class$(String), or // class$(String, boolean). ldcStringConstantIndex = currentConstantIndex; } else { ldcStringConstantIndex = -1; } invokestaticMethodRefConstantIndex = -1; invokevirtualMethodRefConstantIndex = -1; break; case InstructionConstants.OP_INVOKESTATIC: // Are we invoking a static method that might have a constant // String argument? if (ldcStringConstantIndex > 0) { // Check whether the method reference points to Class.forName. if (classForNameChecker.check(clazz, currentConstantIndex)) { // Fill out the class reference in the String. clazz.constantPoolEntryAccept(ldcStringConstantIndex, this); } // We've dealt with this invocation, so we can forget about it. invokestaticMethodRefConstantIndex = -1; } else { // Remember it; it might still be a Class.forName with a // variable String argument. invokestaticMethodRefConstantIndex = currentConstantIndex; } ldcStringConstantIndex = -1; invokevirtualMethodRefConstantIndex = -1; break; case InstructionConstants.OP_INVOKEVIRTUAL: // Are we invoking a virtual method right after a static method? if (invokestaticMethodRefConstantIndex > 0) { // Remember it; it might be Class.newInstance after a Class.forName. invokevirtualMethodRefConstantIndex = currentConstantIndex; } else { invokestaticMethodRefConstantIndex = -1; invokevirtualMethodRefConstantIndex = -1; } ldcStringConstantIndex = -1; break; case InstructionConstants.OP_CHECKCAST: // Are we checking a cast right after a static method and a // virtual method? if (invokestaticMethodRefConstantIndex > 0 && invokevirtualMethodRefConstantIndex > 0) { // Check whether the first method reference points to Class.forName, // and the second method reference to Class.newInstance. if (classForNameChecker.check(clazz, invokestaticMethodRefConstantIndex) && classNewInstanceChecker.check(clazz, invokevirtualMethodRefConstantIndex)) { // Note which class is being cast to. clazz.constantPoolEntryAccept(currentConstantIndex, this); } } // We've handled the special case; forget about the indices. clearConstantPoolIndices(); break; default: // Nothing interesting; just forget any stored indices. clearConstantPoolIndices(); break; } } // Implementations for ConstantVisitor. /** * Fills out the link to the referenced Clazz. */ public void visitStringConstant(Clazz clazz, StringConstant stringConstant) { // Save a reference to the corresponding class. String externalClassName = stringConstant.getString(clazz); String internalClassName = ClassUtil.internalClassName(externalClassName); stringConstant.referencedClass = findClass(internalClassName); } /** * Prints out a note about the class cast to this class, if applicable. */ public void visitClassConstant(Clazz clazz, ClassConstant classConstant) { if (notePrinter != null && (noteExceptionMatcher == null || !noteExceptionMatcher.matches(classConstant.getName(clazz)))) { notePrinter.print("Note: " + ClassUtil.externalClassName(clazz.getName()) + " calls '(" + ClassUtil.externalClassName(classConstant.getName(clazz)) + ")Class.forName(variable).newInstance()'"); } } // Small utility methods. /** * Clears all references to the constant pool. */ private void clearConstantPoolIndices() { ldcStringConstantIndex = -1; invokestaticMethodRefConstantIndex = -1; invokevirtualMethodRefConstantIndex = -1; } /** * Returns the class with the given name, either for the program class pool * or from the library class pool, or <code>null</code> if it can't be found. */ private Clazz findClass(String name) { // First look for the class in the program class pool. Clazz clazz = programClassPool.getClass(name); // Otherwise look for the class in the library class pool. if (clazz == null) { clazz = libraryClassPool.getClass(name); } return clazz; }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -