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 */ 21package proguard.optimize.info; 22 23import proguard.classfile.*; 24import proguard.classfile.attribute.CodeAttribute; 25import proguard.classfile.instruction.*; 26import proguard.classfile.instruction.visitor.InstructionVisitor; 27import proguard.classfile.util.SimplifiedVisitor; 28 29/** 30 * This class can tell whether an instruction might throw exceptions. 31 * 32 * @author Eric Lafortune 33 */ 34public class ExceptionInstructionChecker 35extends SimplifiedVisitor 36implements 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 */ 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 */ 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 */ 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 */ 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 134 public void visitAnyInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, Instruction instruction) {} 135 136 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 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