• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // ASM: a very small and fast Java bytecode manipulation framework
2 // Copyright (c) 2000-2011 INRIA, France Telecom
3 // All rights reserved.
4 //
5 // Redistribution and use in source and binary forms, with or without
6 // modification, are permitted provided that the following conditions
7 // are met:
8 // 1. Redistributions of source code must retain the above copyright
9 //    notice, this list of conditions and the following disclaimer.
10 // 2. Redistributions in binary form must reproduce the above copyright
11 //    notice, this list of conditions and the following disclaimer in the
12 //    documentation and/or other materials provided with the distribution.
13 // 3. Neither the name of the copyright holders nor the names of its
14 //    contributors may be used to endorse or promote products derived from
15 //    this software without specific prior written permission.
16 //
17 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27 // THE POSSIBILITY OF SUCH DAMAGE.
28 package org.objectweb.asm.tree.analysis;
29 
30 import java.util.List;
31 import org.objectweb.asm.Opcodes;
32 import org.objectweb.asm.Type;
33 import org.objectweb.asm.tree.AbstractInsnNode;
34 import org.objectweb.asm.tree.FieldInsnNode;
35 import org.objectweb.asm.tree.InvokeDynamicInsnNode;
36 import org.objectweb.asm.tree.MethodInsnNode;
37 
38 /**
39  * An extended {@link BasicInterpreter} that checks that bytecode instructions are correctly used.
40  *
41  * @author Eric Bruneton
42  * @author Bing Ran
43  */
44 public class BasicVerifier extends BasicInterpreter {
45 
46   /**
47    * Constructs a new {@link BasicVerifier} for the latest ASM API version. <i>Subclasses must not
48    * use this constructor</i>. Instead, they must use the {@link #BasicVerifier(int)} version.
49    */
BasicVerifier()50   public BasicVerifier() {
51     super(/* latest api = */ ASM9);
52     if (getClass() != BasicVerifier.class) {
53       throw new IllegalStateException();
54     }
55   }
56 
57   /**
58    * Constructs a new {@link BasicVerifier}.
59    *
60    * @param api the ASM API version supported by this interpreter. Must be one of the {@code
61    *     ASM}<i>x</i> values in {@link Opcodes}.
62    */
BasicVerifier(final int api)63   protected BasicVerifier(final int api) {
64     super(api);
65   }
66 
67   @Override
copyOperation(final AbstractInsnNode insn, final BasicValue value)68   public BasicValue copyOperation(final AbstractInsnNode insn, final BasicValue value)
69       throws AnalyzerException {
70     Value expected;
71     switch (insn.getOpcode()) {
72       case ILOAD:
73       case ISTORE:
74         expected = BasicValue.INT_VALUE;
75         break;
76       case FLOAD:
77       case FSTORE:
78         expected = BasicValue.FLOAT_VALUE;
79         break;
80       case LLOAD:
81       case LSTORE:
82         expected = BasicValue.LONG_VALUE;
83         break;
84       case DLOAD:
85       case DSTORE:
86         expected = BasicValue.DOUBLE_VALUE;
87         break;
88       case ALOAD:
89         if (!value.isReference()) {
90           throw new AnalyzerException(insn, null, "an object reference", value);
91         }
92         return value;
93       case ASTORE:
94         if (!value.isReference() && !BasicValue.RETURNADDRESS_VALUE.equals(value)) {
95           throw new AnalyzerException(insn, null, "an object reference or a return address", value);
96         }
97         return value;
98       default:
99         return value;
100     }
101     if (!expected.equals(value)) {
102       throw new AnalyzerException(insn, null, expected, value);
103     }
104     return value;
105   }
106 
107   @Override
unaryOperation(final AbstractInsnNode insn, final BasicValue value)108   public BasicValue unaryOperation(final AbstractInsnNode insn, final BasicValue value)
109       throws AnalyzerException {
110     BasicValue expected;
111     switch (insn.getOpcode()) {
112       case INEG:
113       case IINC:
114       case I2F:
115       case I2L:
116       case I2D:
117       case I2B:
118       case I2C:
119       case I2S:
120       case IFEQ:
121       case IFNE:
122       case IFLT:
123       case IFGE:
124       case IFGT:
125       case IFLE:
126       case TABLESWITCH:
127       case LOOKUPSWITCH:
128       case IRETURN:
129       case NEWARRAY:
130       case ANEWARRAY:
131         expected = BasicValue.INT_VALUE;
132         break;
133       case FNEG:
134       case F2I:
135       case F2L:
136       case F2D:
137       case FRETURN:
138         expected = BasicValue.FLOAT_VALUE;
139         break;
140       case LNEG:
141       case L2I:
142       case L2F:
143       case L2D:
144       case LRETURN:
145         expected = BasicValue.LONG_VALUE;
146         break;
147       case DNEG:
148       case D2I:
149       case D2F:
150       case D2L:
151       case DRETURN:
152         expected = BasicValue.DOUBLE_VALUE;
153         break;
154       case GETFIELD:
155         expected = newValue(Type.getObjectType(((FieldInsnNode) insn).owner));
156         break;
157       case ARRAYLENGTH:
158         if (!isArrayValue(value)) {
159           throw new AnalyzerException(insn, null, "an array reference", value);
160         }
161         return super.unaryOperation(insn, value);
162       case CHECKCAST:
163       case ARETURN:
164       case ATHROW:
165       case INSTANCEOF:
166       case MONITORENTER:
167       case MONITOREXIT:
168       case IFNULL:
169       case IFNONNULL:
170         if (!value.isReference()) {
171           throw new AnalyzerException(insn, null, "an object reference", value);
172         }
173         return super.unaryOperation(insn, value);
174       case PUTSTATIC:
175         expected = newValue(Type.getType(((FieldInsnNode) insn).desc));
176         break;
177       default:
178         throw new AssertionError();
179     }
180     if (!isSubTypeOf(value, expected)) {
181       throw new AnalyzerException(insn, null, expected, value);
182     }
183     return super.unaryOperation(insn, value);
184   }
185 
186   @Override
binaryOperation( final AbstractInsnNode insn, final BasicValue value1, final BasicValue value2)187   public BasicValue binaryOperation(
188       final AbstractInsnNode insn, final BasicValue value1, final BasicValue value2)
189       throws AnalyzerException {
190     BasicValue expected1;
191     BasicValue 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 fieldInsn = (FieldInsnNode) insn;
294         expected1 = newValue(Type.getObjectType(fieldInsn.owner));
295         expected2 = newValue(Type.getType(fieldInsn.desc));
296         break;
297       default:
298         throw new AssertionError();
299     }
300     if (!isSubTypeOf(value1, expected1)) {
301       throw new AnalyzerException(insn, "First argument", expected1, value1);
302     } else if (!isSubTypeOf(value2, expected2)) {
303       throw new AnalyzerException(insn, "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 
312   @Override
ternaryOperation( final AbstractInsnNode insn, final BasicValue value1, final BasicValue value2, final BasicValue value3)313   public BasicValue ternaryOperation(
314       final AbstractInsnNode insn,
315       final BasicValue value1,
316       final BasicValue value2,
317       final BasicValue value3)
318       throws AnalyzerException {
319     BasicValue expected1;
320     BasicValue expected3;
321     switch (insn.getOpcode()) {
322       case IASTORE:
323         expected1 = newValue(Type.getType("[I"));
324         expected3 = BasicValue.INT_VALUE;
325         break;
326       case BASTORE:
327         if (isSubTypeOf(value1, newValue(Type.getType("[Z")))) {
328           expected1 = newValue(Type.getType("[Z"));
329         } else {
330           expected1 = newValue(Type.getType("[B"));
331         }
332         expected3 = BasicValue.INT_VALUE;
333         break;
334       case CASTORE:
335         expected1 = newValue(Type.getType("[C"));
336         expected3 = BasicValue.INT_VALUE;
337         break;
338       case SASTORE:
339         expected1 = newValue(Type.getType("[S"));
340         expected3 = BasicValue.INT_VALUE;
341         break;
342       case LASTORE:
343         expected1 = newValue(Type.getType("[J"));
344         expected3 = BasicValue.LONG_VALUE;
345         break;
346       case FASTORE:
347         expected1 = newValue(Type.getType("[F"));
348         expected3 = BasicValue.FLOAT_VALUE;
349         break;
350       case DASTORE:
351         expected1 = newValue(Type.getType("[D"));
352         expected3 = BasicValue.DOUBLE_VALUE;
353         break;
354       case AASTORE:
355         expected1 = value1;
356         expected3 = BasicValue.REFERENCE_VALUE;
357         break;
358       default:
359         throw new AssertionError();
360     }
361     if (!isSubTypeOf(value1, expected1)) {
362       throw new AnalyzerException(
363           insn, "First argument", "a " + expected1 + " array reference", value1);
364     } else if (!BasicValue.INT_VALUE.equals(value2)) {
365       throw new AnalyzerException(insn, "Second argument", BasicValue.INT_VALUE, value2);
366     } else if (!isSubTypeOf(value3, expected3)) {
367       throw new AnalyzerException(insn, "Third argument", expected3, value3);
368     }
369     return null;
370   }
371 
372   @Override
naryOperation( final AbstractInsnNode insn, final List<? extends BasicValue> values)373   public BasicValue naryOperation(
374       final AbstractInsnNode insn, final List<? extends BasicValue> values)
375       throws AnalyzerException {
376     int opcode = insn.getOpcode();
377     if (opcode == MULTIANEWARRAY) {
378       for (BasicValue value : values) {
379         if (!BasicValue.INT_VALUE.equals(value)) {
380           throw new AnalyzerException(insn, null, BasicValue.INT_VALUE, value);
381         }
382       }
383     } else {
384       int i = 0;
385       int j = 0;
386       if (opcode != INVOKESTATIC && opcode != INVOKEDYNAMIC) {
387         Type owner = Type.getObjectType(((MethodInsnNode) insn).owner);
388         if (!isSubTypeOf(values.get(i++), newValue(owner))) {
389           throw new AnalyzerException(insn, "Method owner", newValue(owner), values.get(0));
390         }
391       }
392       String methodDescriptor =
393           (opcode == INVOKEDYNAMIC)
394               ? ((InvokeDynamicInsnNode) insn).desc
395               : ((MethodInsnNode) insn).desc;
396       Type[] args = Type.getArgumentTypes(methodDescriptor);
397       while (i < values.size()) {
398         BasicValue expected = newValue(args[j++]);
399         BasicValue actual = values.get(i++);
400         if (!isSubTypeOf(actual, expected)) {
401           throw new AnalyzerException(insn, "Argument " + j, expected, actual);
402         }
403       }
404     }
405     return super.naryOperation(insn, values);
406   }
407 
408   @Override
returnOperation( final AbstractInsnNode insn, final BasicValue value, final BasicValue expected)409   public void returnOperation(
410       final AbstractInsnNode insn, final BasicValue value, final BasicValue expected)
411       throws AnalyzerException {
412     if (!isSubTypeOf(value, expected)) {
413       throw new AnalyzerException(insn, "Incompatible return type", expected, value);
414     }
415   }
416 
417   /**
418    * Returns whether the given value corresponds to an array reference.
419    *
420    * @param value a value.
421    * @return whether 'value' corresponds to an array reference.
422    */
isArrayValue(final BasicValue value)423   protected boolean isArrayValue(final BasicValue value) {
424     return value.isReference();
425   }
426 
427   /**
428    * Returns the value corresponding to the type of the elements of the given array reference value.
429    *
430    * @param objectArrayValue a value corresponding to array of object (or array) references.
431    * @return the value corresponding to the type of the elements of 'objectArrayValue'.
432    * @throws AnalyzerException if objectArrayValue does not correspond to an array type.
433    */
getElementValue(final BasicValue objectArrayValue)434   protected BasicValue getElementValue(final BasicValue objectArrayValue) throws AnalyzerException {
435     return BasicValue.REFERENCE_VALUE;
436   }
437 
438   /**
439    * Returns whether the type corresponding to the first argument is a subtype of the type
440    * corresponding to the second argument.
441    *
442    * @param value a value.
443    * @param expected another value.
444    * @return whether the type corresponding to 'value' is a subtype of the type corresponding to
445    *     'expected'.
446    */
isSubTypeOf(final BasicValue value, final BasicValue expected)447   protected boolean isSubTypeOf(final BasicValue value, final BasicValue expected) {
448     return value.equals(expected);
449   }
450 }
451