• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /***
2  * ASM: a very small and fast Java bytecode manipulation framework
3  * Copyright (c) 2000-2007 INRIA, France Telecom
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  * 3. Neither the name of the copyright holders nor the names of its
15  *    contributors may be used to endorse or promote products derived from
16  *    this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
22  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
28  * THE POSSIBILITY OF SUCH DAMAGE.
29  */
30 package org.mockito.asm.tree.analysis;
31 
32 import java.util.List;
33 
34 import org.mockito.asm.Type;
35 import org.mockito.asm.tree.AbstractInsnNode;
36 import org.mockito.asm.tree.FieldInsnNode;
37 import org.mockito.asm.tree.MethodInsnNode;
38 
39 /**
40  * An extended {@link BasicInterpreter} that checks that bytecode instructions
41  * are correctly used.
42  *
43  * @author Eric Bruneton
44  * @author Bing Ran
45  */
46 public class BasicVerifier extends BasicInterpreter {
47 
copyOperation(final AbstractInsnNode insn, final Value value)48     public Value copyOperation(final AbstractInsnNode insn, final Value value)
49             throws AnalyzerException
50     {
51         Value expected;
52         switch (insn.getOpcode()) {
53             case ILOAD:
54             case ISTORE:
55                 expected = BasicValue.INT_VALUE;
56                 break;
57             case FLOAD:
58             case FSTORE:
59                 expected = BasicValue.FLOAT_VALUE;
60                 break;
61             case LLOAD:
62             case LSTORE:
63                 expected = BasicValue.LONG_VALUE;
64                 break;
65             case DLOAD:
66             case DSTORE:
67                 expected = BasicValue.DOUBLE_VALUE;
68                 break;
69             case ALOAD:
70                 if (!((BasicValue) value).isReference()) {
71                     throw new AnalyzerException(null,
72                             "an object reference",
73                             value);
74                 }
75                 return value;
76             case ASTORE:
77                 if (!((BasicValue) value).isReference()
78                         && value != BasicValue.RETURNADDRESS_VALUE)
79                 {
80                     throw new AnalyzerException(null,
81                             "an object reference or a return address",
82                             value);
83                 }
84                 return value;
85             default:
86                 return value;
87         }
88         // type is necessarily a primitive type here,
89         // so value must be == to expected value
90         if (value != expected) {
91             throw new AnalyzerException(null, expected, value);
92         }
93         return value;
94     }
95 
unaryOperation(final AbstractInsnNode insn, final Value value)96     public Value unaryOperation(final AbstractInsnNode insn, final Value value)
97             throws AnalyzerException
98     {
99         Value expected;
100         switch (insn.getOpcode()) {
101             case INEG:
102             case IINC:
103             case I2F:
104             case I2L:
105             case I2D:
106             case I2B:
107             case I2C:
108             case I2S:
109             case IFEQ:
110             case IFNE:
111             case IFLT:
112             case IFGE:
113             case IFGT:
114             case IFLE:
115             case TABLESWITCH:
116             case LOOKUPSWITCH:
117             case IRETURN:
118             case NEWARRAY:
119             case ANEWARRAY:
120                 expected = BasicValue.INT_VALUE;
121                 break;
122             case FNEG:
123             case F2I:
124             case F2L:
125             case F2D:
126             case FRETURN:
127                 expected = BasicValue.FLOAT_VALUE;
128                 break;
129             case LNEG:
130             case L2I:
131             case L2F:
132             case L2D:
133             case LRETURN:
134                 expected = BasicValue.LONG_VALUE;
135                 break;
136             case DNEG:
137             case D2I:
138             case D2F:
139             case D2L:
140             case DRETURN:
141                 expected = BasicValue.DOUBLE_VALUE;
142                 break;
143             case GETFIELD:
144                 expected = newValue(Type.getObjectType(((FieldInsnNode) insn).owner));
145                 break;
146             case CHECKCAST:
147                 if (!((BasicValue) value).isReference()) {
148                     throw new AnalyzerException(null,
149                             "an object reference",
150                             value);
151                 }
152                 return super.unaryOperation(insn, value);
153             case ARRAYLENGTH:
154                 if (!isArrayValue(value)) {
155                     throw new AnalyzerException(null,
156                             "an array reference",
157                             value);
158                 }
159                 return super.unaryOperation(insn, value);
160             case ARETURN:
161             case ATHROW:
162             case INSTANCEOF:
163             case MONITORENTER:
164             case MONITOREXIT:
165             case IFNULL:
166             case IFNONNULL:
167                 if (!((BasicValue) value).isReference()) {
168                     throw new AnalyzerException(null,
169                             "an object reference",
170                             value);
171                 }
172                 return super.unaryOperation(insn, value);
173             case PUTSTATIC:
174                 expected = newValue(Type.getType(((FieldInsnNode) insn).desc));
175                 break;
176             default:
177                 throw new Error("Internal error.");
178         }
179         if (!isSubTypeOf(value, expected)) {
180             throw new AnalyzerException(null, expected, value);
181         }
182         return super.unaryOperation(insn, value);
183     }
184 
binaryOperation( final AbstractInsnNode insn, final Value value1, final Value value2)185     public Value binaryOperation(
186         final AbstractInsnNode insn,
187         final Value value1,
188         final Value value2) throws AnalyzerException
189     {
190         Value expected1;
191         Value expected2;
192         switch (insn.getOpcode()) {
193             case IALOAD:
194                 expected1 = newValue(Type.getType("[I"));
195                 expected2 = BasicValue.INT_VALUE;
196                 break;
197             case BALOAD:
198                 if (isSubTypeOf(value1, newValue(Type.getType("[Z")))) {
199                     expected1 = newValue(Type.getType("[Z"));
200                 } else {
201                     expected1 = newValue(Type.getType("[B"));
202                 }
203                 expected2 = BasicValue.INT_VALUE;
204                 break;
205             case CALOAD:
206                 expected1 = newValue(Type.getType("[C"));
207                 expected2 = BasicValue.INT_VALUE;
208                 break;
209             case SALOAD:
210                 expected1 = newValue(Type.getType("[S"));
211                 expected2 = BasicValue.INT_VALUE;
212                 break;
213             case LALOAD:
214                 expected1 = newValue(Type.getType("[J"));
215                 expected2 = BasicValue.INT_VALUE;
216                 break;
217             case FALOAD:
218                 expected1 = newValue(Type.getType("[F"));
219                 expected2 = BasicValue.INT_VALUE;
220                 break;
221             case DALOAD:
222                 expected1 = newValue(Type.getType("[D"));
223                 expected2 = BasicValue.INT_VALUE;
224                 break;
225             case AALOAD:
226                 expected1 = newValue(Type.getType("[Ljava/lang/Object;"));
227                 expected2 = BasicValue.INT_VALUE;
228                 break;
229             case IADD:
230             case ISUB:
231             case IMUL:
232             case IDIV:
233             case IREM:
234             case ISHL:
235             case ISHR:
236             case IUSHR:
237             case IAND:
238             case IOR:
239             case IXOR:
240             case IF_ICMPEQ:
241             case IF_ICMPNE:
242             case IF_ICMPLT:
243             case IF_ICMPGE:
244             case IF_ICMPGT:
245             case IF_ICMPLE:
246                 expected1 = BasicValue.INT_VALUE;
247                 expected2 = BasicValue.INT_VALUE;
248                 break;
249             case FADD:
250             case FSUB:
251             case FMUL:
252             case FDIV:
253             case FREM:
254             case FCMPL:
255             case FCMPG:
256                 expected1 = BasicValue.FLOAT_VALUE;
257                 expected2 = BasicValue.FLOAT_VALUE;
258                 break;
259             case LADD:
260             case LSUB:
261             case LMUL:
262             case LDIV:
263             case LREM:
264             case LAND:
265             case LOR:
266             case LXOR:
267             case LCMP:
268                 expected1 = BasicValue.LONG_VALUE;
269                 expected2 = BasicValue.LONG_VALUE;
270                 break;
271             case LSHL:
272             case LSHR:
273             case LUSHR:
274                 expected1 = BasicValue.LONG_VALUE;
275                 expected2 = BasicValue.INT_VALUE;
276                 break;
277             case DADD:
278             case DSUB:
279             case DMUL:
280             case DDIV:
281             case DREM:
282             case DCMPL:
283             case DCMPG:
284                 expected1 = BasicValue.DOUBLE_VALUE;
285                 expected2 = BasicValue.DOUBLE_VALUE;
286                 break;
287             case IF_ACMPEQ:
288             case IF_ACMPNE:
289                 expected1 = BasicValue.REFERENCE_VALUE;
290                 expected2 = BasicValue.REFERENCE_VALUE;
291                 break;
292             case PUTFIELD:
293                 FieldInsnNode fin = (FieldInsnNode) insn;
294                 expected1 = newValue(Type.getObjectType(fin.owner));
295                 expected2 = newValue(Type.getType(fin.desc));
296                 break;
297             default:
298                 throw new Error("Internal error.");
299         }
300         if (!isSubTypeOf(value1, expected1)) {
301             throw new AnalyzerException("First argument", expected1, value1);
302         } else if (!isSubTypeOf(value2, expected2)) {
303             throw new AnalyzerException("Second argument", expected2, value2);
304         }
305         if (insn.getOpcode() == AALOAD) {
306             return getElementValue(value1);
307         } else {
308             return super.binaryOperation(insn, value1, value2);
309         }
310     }
311 
ternaryOperation( final AbstractInsnNode insn, final Value value1, final Value value2, final Value value3)312     public Value ternaryOperation(
313         final AbstractInsnNode insn,
314         final Value value1,
315         final Value value2,
316         final Value value3) throws AnalyzerException
317     {
318         Value expected1;
319         Value expected3;
320         switch (insn.getOpcode()) {
321             case IASTORE:
322                 expected1 = newValue(Type.getType("[I"));
323                 expected3 = BasicValue.INT_VALUE;
324                 break;
325             case BASTORE:
326                 if (isSubTypeOf(value1, newValue(Type.getType("[Z")))) {
327                     expected1 = newValue(Type.getType("[Z"));
328                 } else {
329                     expected1 = newValue(Type.getType("[B"));
330                 }
331                 expected3 = BasicValue.INT_VALUE;
332                 break;
333             case CASTORE:
334                 expected1 = newValue(Type.getType("[C"));
335                 expected3 = BasicValue.INT_VALUE;
336                 break;
337             case SASTORE:
338                 expected1 = newValue(Type.getType("[S"));
339                 expected3 = BasicValue.INT_VALUE;
340                 break;
341             case LASTORE:
342                 expected1 = newValue(Type.getType("[J"));
343                 expected3 = BasicValue.LONG_VALUE;
344                 break;
345             case FASTORE:
346                 expected1 = newValue(Type.getType("[F"));
347                 expected3 = BasicValue.FLOAT_VALUE;
348                 break;
349             case DASTORE:
350                 expected1 = newValue(Type.getType("[D"));
351                 expected3 = BasicValue.DOUBLE_VALUE;
352                 break;
353             case AASTORE:
354                 expected1 = value1;
355                 expected3 = BasicValue.REFERENCE_VALUE;
356                 break;
357             default:
358                 throw new Error("Internal error.");
359         }
360         if (!isSubTypeOf(value1, expected1)) {
361             throw new AnalyzerException("First argument", "a " + expected1
362                     + " array reference", value1);
363         } else if (value2 != BasicValue.INT_VALUE) {
364             throw new AnalyzerException("Second argument",
365                     BasicValue.INT_VALUE,
366                     value2);
367         } else if (!isSubTypeOf(value3, expected3)) {
368             throw new AnalyzerException("Third argument", expected3, value3);
369         }
370         return null;
371     }
372 
naryOperation(final AbstractInsnNode insn, final List values)373     public Value naryOperation(final AbstractInsnNode insn, final List values)
374             throws AnalyzerException
375     {
376         int opcode = insn.getOpcode();
377         if (opcode == MULTIANEWARRAY) {
378             for (int i = 0; i < values.size(); ++i) {
379                 if (values.get(i) != BasicValue.INT_VALUE) {
380                     throw new AnalyzerException(null,
381                             BasicValue.INT_VALUE,
382                             (Value) values.get(i));
383                 }
384             }
385         } else {
386             int i = 0;
387             int j = 0;
388             if (opcode != INVOKESTATIC) {
389                 Type owner = Type.getObjectType(((MethodInsnNode) insn).owner);
390                 if (!isSubTypeOf((Value) values.get(i++), newValue(owner))) {
391                     throw new AnalyzerException("Method owner",
392                             newValue(owner),
393                             (Value) values.get(0));
394                 }
395             }
396             Type[] args = Type.getArgumentTypes(((MethodInsnNode) insn).desc);
397             while (i < values.size()) {
398                 Value expected = newValue(args[j++]);
399                 Value encountered = (Value) values.get(i++);
400                 if (!isSubTypeOf(encountered, expected)) {
401                     throw new AnalyzerException("Argument " + j,
402                             expected,
403                             encountered);
404                 }
405             }
406         }
407         return super.naryOperation(insn, values);
408     }
409 
isArrayValue(final Value value)410     protected boolean isArrayValue(final Value value) {
411         return ((BasicValue) value).isReference();
412     }
413 
getElementValue(final Value objectArrayValue)414     protected Value getElementValue(final Value objectArrayValue)
415             throws AnalyzerException
416     {
417         return BasicValue.REFERENCE_VALUE;
418     }
419 
isSubTypeOf(final Value value, final Value expected)420     protected boolean isSubTypeOf(final Value value, final Value expected) {
421         return value == expected;
422     }
423 }
424