1 /* 2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 3 * 4 * This code is free software; you can redistribute it and/or modify it 5 * under the terms of the GNU General Public License version 2 only, as 6 * published by the Free Software Foundation. Oracle designates this 7 * particular file as subject to the "Classpath" exception as provided 8 * by Oracle in the LICENSE file that accompanied this code. 9 * 10 * This code is distributed in the hope that it will be useful, but WITHOUT 11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 13 * version 2 for more details (a copy is included in the LICENSE file that 14 * accompanied this code). 15 * 16 * You should have received a copy of the GNU General Public License version 17 * 2 along with this work; if not, write to the Free Software Foundation, 18 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 19 * 20 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 21 * or visit www.oracle.com if you need additional information or have any 22 * questions. 23 */ 24 25 /* 26 * This file is available under and governed by the GNU General Public 27 * License version 2 only, as published by the Free Software Foundation. 28 * However, the following notice accompanied the original version of this 29 * file: 30 * 31 * ASM: a very small and fast Java bytecode manipulation framework 32 * Copyright (c) 2000-2011 INRIA, France Telecom 33 * All rights reserved. 34 * 35 * Redistribution and use in source and binary forms, with or without 36 * modification, are permitted provided that the following conditions 37 * are met: 38 * 1. Redistributions of source code must retain the above copyright 39 * notice, this list of conditions and the following disclaimer. 40 * 2. Redistributions in binary form must reproduce the above copyright 41 * notice, this list of conditions and the following disclaimer in the 42 * documentation and/or other materials provided with the distribution. 43 * 3. Neither the name of the copyright holders nor the names of its 44 * contributors may be used to endorse or promote products derived from 45 * this software without specific prior written permission. 46 * 47 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 48 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 49 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 50 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 51 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 52 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 53 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 54 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 55 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 56 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 57 * THE POSSIBILITY OF SUCH DAMAGE. 58 */ 59 package jdk.internal.org.objectweb.asm.tree.analysis; 60 61 import java.util.List; 62 63 import jdk.internal.org.objectweb.asm.Type; 64 65 /** 66 * An extended {@link BasicVerifier} that performs more precise verifications. 67 * This verifier computes exact class types, instead of using a single "object 68 * reference" type (as done in the {@link BasicVerifier}). 69 * 70 * @author Eric Bruneton 71 * @author Bing Ran 72 */ 73 public class SimpleVerifier extends BasicVerifier { 74 75 /** 76 * The class that is verified. 77 */ 78 private final Type currentClass; 79 80 /** 81 * The super class of the class that is verified. 82 */ 83 private final Type currentSuperClass; 84 85 /** 86 * The interfaces implemented by the class that is verified. 87 */ 88 private final List<Type> currentClassInterfaces; 89 90 /** 91 * If the class that is verified is an interface. 92 */ 93 private final boolean isInterface; 94 95 /** 96 * The loader to use for referenced classes. 97 */ 98 private ClassLoader loader = getClass().getClassLoader(); 99 100 /** 101 * Constructs a new {@link SimpleVerifier}. 102 */ 103 public SimpleVerifier() { 104 this(null, null, false); 105 } 106 107 /** 108 * Constructs a new {@link SimpleVerifier} to verify a specific class. This 109 * class will not be loaded into the JVM since it may be incorrect. 110 * 111 * @param currentClass 112 * the class that is verified. 113 * @param currentSuperClass 114 * the super class of the class that is verified. 115 * @param isInterface 116 * if the class that is verified is an interface. 117 */ 118 public SimpleVerifier(final Type currentClass, 119 final Type currentSuperClass, final boolean isInterface) { 120 this(currentClass, currentSuperClass, null, isInterface); 121 } 122 123 /** 124 * Constructs a new {@link SimpleVerifier} to verify a specific class. This 125 * class will not be loaded into the JVM since it may be incorrect. 126 * 127 * @param currentClass 128 * the class that is verified. 129 * @param currentSuperClass 130 * the super class of the class that is verified. 131 * @param currentClassInterfaces 132 * the interfaces implemented by the class that is verified. 133 * @param isInterface 134 * if the class that is verified is an interface. 135 */ 136 public SimpleVerifier(final Type currentClass, 137 final Type currentSuperClass, 138 final List<Type> currentClassInterfaces, final boolean isInterface) { 139 this(ASM5, currentClass, currentSuperClass, currentClassInterfaces, 140 isInterface); 141 } 142 143 protected SimpleVerifier(final int api, final Type currentClass, 144 final Type currentSuperClass, 145 final List<Type> currentClassInterfaces, final boolean isInterface) { 146 super(api); 147 this.currentClass = currentClass; 148 this.currentSuperClass = currentSuperClass; 149 this.currentClassInterfaces = currentClassInterfaces; 150 this.isInterface = isInterface; 151 } 152 153 /** 154 * Set the <code>ClassLoader</code> which will be used to load referenced 155 * classes. This is useful if you are verifying multiple interdependent 156 * classes. 157 * 158 * @param loader 159 * a <code>ClassLoader</code> to use 160 */ 161 public void setClassLoader(final ClassLoader loader) { 162 this.loader = loader; 163 } 164 165 @Override 166 public BasicValue newValue(final Type type) { 167 if (type == null) { 168 return BasicValue.UNINITIALIZED_VALUE; 169 } 170 171 boolean isArray = type.getSort() == Type.ARRAY; 172 if (isArray) { 173 switch (type.getElementType().getSort()) { 174 case Type.BOOLEAN: 175 case Type.CHAR: 176 case Type.BYTE: 177 case Type.SHORT: 178 return new BasicValue(type); 179 } 180 } 181 182 BasicValue v = super.newValue(type); 183 if (BasicValue.REFERENCE_VALUE.equals(v)) { 184 if (isArray) { 185 v = newValue(type.getElementType()); 186 String desc = v.getType().getDescriptor(); 187 for (int i = 0; i < type.getDimensions(); ++i) { 188 desc = '[' + desc; 189 } 190 v = new BasicValue(Type.getType(desc)); 191 } else { 192 v = new BasicValue(type); 193 } 194 } 195 return v; 196 } 197 198 @Override 199 protected boolean isArrayValue(final BasicValue value) { 200 Type t = value.getType(); 201 return t != null 202 && ("Lnull;".equals(t.getDescriptor()) || t.getSort() == Type.ARRAY); 203 } 204 205 @Override 206 protected BasicValue getElementValue(final BasicValue objectArrayValue) 207 throws AnalyzerException { 208 Type arrayType = objectArrayValue.getType(); 209 if (arrayType != null) { 210 if (arrayType.getSort() == Type.ARRAY) { 211 return newValue(Type.getType(arrayType.getDescriptor() 212 .substring(1))); 213 } else if ("Lnull;".equals(arrayType.getDescriptor())) { 214 return objectArrayValue; 215 } 216 } 217 throw new Error("Internal error"); 218 } 219 220 @Override 221 protected boolean isSubTypeOf(final BasicValue value, 222 final BasicValue expected) { 223 Type expectedType = expected.getType(); 224 Type type = value.getType(); 225 switch (expectedType.getSort()) { 226 case Type.INT: 227 case Type.FLOAT: 228 case Type.LONG: 229 case Type.DOUBLE: 230 return type.equals(expectedType); 231 case Type.ARRAY: 232 case Type.OBJECT: 233 if ("Lnull;".equals(type.getDescriptor())) { 234 return true; 235 } else if (type.getSort() == Type.OBJECT 236 || type.getSort() == Type.ARRAY) { 237 return isAssignableFrom(expectedType, type); 238 } else { 239 return false; 240 } 241 default: 242 throw new Error("Internal error"); 243 } 244 } 245 246 @Override 247 public BasicValue merge(final BasicValue v, final BasicValue w) { 248 if (!v.equals(w)) { 249 Type t = v.getType(); 250 Type u = w.getType(); 251 if (t != null 252 && (t.getSort() == Type.OBJECT || t.getSort() == Type.ARRAY)) { 253 if (u != null 254 && (u.getSort() == Type.OBJECT || u.getSort() == Type.ARRAY)) { 255 if ("Lnull;".equals(t.getDescriptor())) { 256 return w; 257 } 258 if ("Lnull;".equals(u.getDescriptor())) { 259 return v; 260 } 261 if (isAssignableFrom(t, u)) { 262 return v; 263 } 264 if (isAssignableFrom(u, t)) { 265 return w; 266 } 267 // TODO case of array classes of the same dimension 268 // TODO should we look also for a common super interface? 269 // problem: there may be several possible common super 270 // interfaces 271 do { 272 if (t == null || isInterface(t)) { 273 return BasicValue.REFERENCE_VALUE; 274 } 275 t = getSuperClass(t); 276 if (isAssignableFrom(t, u)) { 277 return newValue(t); 278 } 279 } while (true); 280 } 281 } 282 return BasicValue.UNINITIALIZED_VALUE; 283 } 284 return v; 285 } 286 287 protected boolean isInterface(final Type t) { 288 if (currentClass != null && t.equals(currentClass)) { 289 return isInterface; 290 } 291 return getClass(t).isInterface(); 292 } 293 294 protected Type getSuperClass(final Type t) { 295 if (currentClass != null && t.equals(currentClass)) { 296 return currentSuperClass; 297 } 298 Class<?> c = getClass(t).getSuperclass(); 299 return c == null ? null : Type.getType(c); 300 } 301 302 protected boolean isAssignableFrom(final Type t, final Type u) { 303 if (t.equals(u)) { 304 return true; 305 } 306 if (currentClass != null && t.equals(currentClass)) { 307 if (getSuperClass(u) == null) { 308 return false; 309 } else { 310 if (isInterface) { 311 return u.getSort() == Type.OBJECT 312 || u.getSort() == Type.ARRAY; 313 } 314 return isAssignableFrom(t, getSuperClass(u)); 315 } 316 } 317 if (currentClass != null && u.equals(currentClass)) { 318 if (isAssignableFrom(t, currentSuperClass)) { 319 return true; 320 } 321 if (currentClassInterfaces != null) { 322 for (int i = 0; i < currentClassInterfaces.size(); ++i) { 323 Type v = currentClassInterfaces.get(i); 324 if (isAssignableFrom(t, v)) { 325 return true; 326 } 327 } 328 } 329 return false; 330 } 331 Class<?> tc = getClass(t); 332 if (tc.isInterface()) { 333 tc = Object.class; 334 } 335 return tc.isAssignableFrom(getClass(u)); 336 } 337 338 protected Class<?> getClass(final Type t) { 339 try { 340 if (t.getSort() == Type.ARRAY) { 341 return Class.forName(t.getDescriptor().replace('/', '.'), 342 false, loader); 343 } 344 return Class.forName(t.getClassName(), false, loader); 345 } catch (ClassNotFoundException e) { 346 throw new RuntimeException(e.toString()); 347 } 348 } 349 }