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