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