1 /* 2 * ProGuard -- shrinking, optimization, obfuscation, and preverification 3 * of Java bytecode. 4 * 5 * Copyright (c) 2002-2014 Eric Lafortune (eric@graphics.cornell.edu) 6 * 7 * This program is free software; you can redistribute it and/or modify it 8 * under the terms of the GNU General Public License as published by the Free 9 * Software Foundation; either version 2 of the License, or (at your option) 10 * any later version. 11 * 12 * This program is distributed in the hope that it will be useful, but WITHOUT 13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 15 * more details. 16 * 17 * You should have received a copy of the GNU General Public License along 18 * with this program; if not, write to the Free Software Foundation, Inc., 19 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 20 */ 21 package proguard.optimize.info; 22 23 import proguard.classfile.*; 24 import proguard.classfile.attribute.CodeAttribute; 25 import proguard.classfile.instruction.*; 26 import proguard.classfile.instruction.visitor.InstructionVisitor; 27 import proguard.classfile.util.SimplifiedVisitor; 28 29 /** 30 * This class can tell whether an instruction might throw exceptions. 31 * 32 * @author Eric Lafortune 33 */ 34 public class ExceptionInstructionChecker 35 extends SimplifiedVisitor 36 implements InstructionVisitor 37 // ConstantVisitor, 38 // MemberVisitor 39 { 40 // A return value for the visitor methods. 41 private boolean mayThrowExceptions; 42 43 44 /** 45 * Returns whether the specified method may throw exceptions. 46 */ mayThrowExceptions(Clazz clazz, Method method, CodeAttribute codeAttribute)47 public boolean mayThrowExceptions(Clazz clazz, 48 Method method, 49 CodeAttribute codeAttribute) 50 { 51 return mayThrowExceptions(clazz, 52 method, 53 codeAttribute, 54 0, 55 codeAttribute.u4codeLength); 56 } 57 58 59 /** 60 * Returns whether the specified block of code may throw exceptions. 61 */ mayThrowExceptions(Clazz clazz, Method method, CodeAttribute codeAttribute, int startOffset, int endOffset)62 public boolean mayThrowExceptions(Clazz clazz, 63 Method method, 64 CodeAttribute codeAttribute, 65 int startOffset, 66 int endOffset) 67 { 68 byte[] code = codeAttribute.code; 69 70 // Go over all instructions. 71 int offset = startOffset; 72 while (offset < endOffset) 73 { 74 // Get the current instruction. 75 Instruction instruction = InstructionFactory.create(code, offset); 76 77 // Check if it may be throwing exceptions. 78 if (mayThrowExceptions(clazz, 79 method, 80 codeAttribute, 81 offset, 82 instruction)) 83 { 84 return true; 85 } 86 87 // Go to the next instruction. 88 offset += instruction.length(offset); 89 } 90 91 return false; 92 } 93 94 95 /** 96 * Returns whether the specified instruction may throw exceptions. 97 */ mayThrowExceptions(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset)98 public boolean mayThrowExceptions(Clazz clazz, 99 Method method, 100 CodeAttribute codeAttribute, 101 int offset) 102 { 103 Instruction instruction = InstructionFactory.create(codeAttribute.code, offset); 104 105 return mayThrowExceptions(clazz, 106 method, 107 codeAttribute, 108 offset, 109 instruction); 110 } 111 112 113 /** 114 * Returns whether the given instruction may throw exceptions. 115 */ mayThrowExceptions(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, Instruction instruction)116 public boolean mayThrowExceptions(Clazz clazz, 117 Method method, 118 CodeAttribute codeAttribute, 119 int offset, 120 Instruction instruction) 121 { 122 return instruction.mayThrowExceptions(); 123 124 // mayThrowExceptions = false; 125 // 126 // instruction.accept(clazz, method, codeAttribute, offset, this); 127 // 128 // return mayThrowExceptions; 129 } 130 131 132 // Implementations for InstructionVisitor. 133 visitAnyInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, Instruction instruction)134 public void visitAnyInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, Instruction instruction) {} 135 136 visitSimpleInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, SimpleInstruction simpleInstruction)137 public void visitSimpleInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, SimpleInstruction simpleInstruction) 138 { 139 // Check for instructions that may throw exceptions. 140 // Note that monitorexit can not sensibly throw exceptions, except the 141 // broken and deprecated asynchronous ThreadDeath. Removing the 142 // artificial infinite looping exception blocks that recent compilers 143 // add does not strictly follow the JVM specs, but it does have the 144 // additional benefit of avoiding a bug in the JVM in JDK 1.1. 145 switch (simpleInstruction.opcode) 146 { 147 case InstructionConstants.OP_IDIV: 148 case InstructionConstants.OP_LDIV: 149 case InstructionConstants.OP_IREM: 150 case InstructionConstants.OP_LREM: 151 case InstructionConstants.OP_IALOAD: 152 case InstructionConstants.OP_LALOAD: 153 case InstructionConstants.OP_FALOAD: 154 case InstructionConstants.OP_DALOAD: 155 case InstructionConstants.OP_AALOAD: 156 case InstructionConstants.OP_BALOAD: 157 case InstructionConstants.OP_CALOAD: 158 case InstructionConstants.OP_SALOAD: 159 case InstructionConstants.OP_IASTORE: 160 case InstructionConstants.OP_LASTORE: 161 case InstructionConstants.OP_FASTORE: 162 case InstructionConstants.OP_DASTORE: 163 case InstructionConstants.OP_AASTORE: 164 case InstructionConstants.OP_BASTORE: 165 case InstructionConstants.OP_CASTORE: 166 case InstructionConstants.OP_SASTORE: 167 case InstructionConstants.OP_NEWARRAY: 168 case InstructionConstants.OP_ARRAYLENGTH: 169 case InstructionConstants.OP_ATHROW: 170 case InstructionConstants.OP_MONITORENTER: 171 // These instructions may throw exceptions. 172 mayThrowExceptions = true; 173 } 174 } 175 176 visitConstantInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, ConstantInstruction constantInstruction)177 public void visitConstantInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, ConstantInstruction constantInstruction) 178 { 179 // Check for instructions that may throw exceptions. 180 switch (constantInstruction.opcode) 181 { 182 case InstructionConstants.OP_GETSTATIC: 183 case InstructionConstants.OP_PUTSTATIC: 184 case InstructionConstants.OP_GETFIELD: 185 case InstructionConstants.OP_PUTFIELD: 186 case InstructionConstants.OP_INVOKEVIRTUAL: 187 case InstructionConstants.OP_INVOKESPECIAL: 188 case InstructionConstants.OP_INVOKESTATIC: 189 case InstructionConstants.OP_INVOKEINTERFACE: 190 case InstructionConstants.OP_INVOKEDYNAMIC: 191 case InstructionConstants.OP_NEW: 192 case InstructionConstants.OP_ANEWARRAY: 193 case InstructionConstants.OP_CHECKCAST: 194 case InstructionConstants.OP_INSTANCEOF: 195 case InstructionConstants.OP_MULTIANEWARRAY: 196 // These instructions may throw exceptions. 197 mayThrowExceptions = true; 198 199 // case InstructionConstants.OP_INVOKEVIRTUAL: 200 // case InstructionConstants.OP_INVOKESPECIAL: 201 // case InstructionConstants.OP_INVOKESTATIC: 202 // case InstructionConstants.OP_INVOKEINTERFACE: 203 // // Check if the invoking the method may throw an exception. 204 // clazz.constantPoolEntryAccept(constantInstruction.constantIndex, this); 205 } 206 } 207 208 209 // // Implementations for ConstantVisitor. 210 // 211 // public void visitAnyMethodrefConstant(Clazz clazz, RefConstant refConstant) 212 // { 213 // Member referencedMember = refConstant.referencedMember; 214 // 215 // // Do we have a reference to the method? 216 // if (referencedMember == null) 217 // { 218 // // We'll have to assume invoking the unknown method may throw an 219 // // an exception. 220 // mayThrowExceptions = true; 221 // } 222 // else 223 // { 224 // // First check the referenced method itself. 225 // refConstant.referencedMemberAccept(this); 226 // 227 // // If the result isn't conclusive, check down the hierarchy. 228 // if (!mayThrowExceptions) 229 // { 230 // Clazz referencedClass = refConstant.referencedClass; 231 // Method referencedMethod = (Method)referencedMember; 232 // 233 // // Check all other implementations of the method in the class 234 // // hierarchy. 235 // referencedClass.methodImplementationsAccept(referencedMethod, 236 // false, 237 // false, 238 // true, 239 // true, 240 // this); 241 // } 242 // } 243 // } 244 // 245 // 246 // // Implementations for MemberVisitor. 247 // 248 // public void visitProgramMethod(ProgramClass programClass, ProgramMethod programMethod) 249 // { 250 // mayThrowExceptions = mayThrowExceptions || 251 // ExceptionMethodMarker.mayThrowExceptions(programMethod); 252 // } 253 // 254 // 255 // public void visitLibraryMethod(LibraryClass libraryClass, LibraryMethod libraryMethod) 256 // { 257 // mayThrowExceptions = mayThrowExceptions || 258 // !NoExceptionMethodMarker.doesntThrowExceptions(libraryMethod); 259 // } 260 } 261