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.util; 60 61 import java.util.EnumSet; 62 import jdk.internal.org.objectweb.asm.Opcodes; 63 import jdk.internal.org.objectweb.asm.signature.SignatureVisitor; 64 65 /** 66 * A {@link SignatureVisitor} that checks that its methods are properly used. 67 * 68 * @author Eric Bruneton 69 */ 70 public class CheckSignatureAdapter extends SignatureVisitor { 71 72 /** 73 * Type to be used to check class signatures. See {@link #CheckSignatureAdapter(int, 74 * SignatureVisitor)}. 75 */ 76 public static final int CLASS_SIGNATURE = 0; 77 78 /** 79 * Type to be used to check method signatures. See {@link #CheckSignatureAdapter(int, 80 * SignatureVisitor)}. 81 */ 82 public static final int METHOD_SIGNATURE = 1; 83 84 /** 85 * Type to be used to check type signatures.See {@link #CheckSignatureAdapter(int, 86 * SignatureVisitor)}. 87 */ 88 public static final int TYPE_SIGNATURE = 2; 89 90 /** The valid automaton states for a {@link #visitFormalTypeParameter} method call. */ 91 private static final EnumSet<State> VISIT_FORMAL_TYPE_PARAMETER_STATES = 92 EnumSet.of(State.EMPTY, State.FORMAL, State.BOUND); 93 94 /** The valid automaton states for a {@link #visitClassBound} method call. */ 95 private static final EnumSet<State> VISIT_CLASS_BOUND_STATES = EnumSet.of(State.FORMAL); 96 97 /** The valid automaton states for a {@link #visitInterfaceBound} method call. */ 98 private static final EnumSet<State> VISIT_INTERFACE_BOUND_STATES = 99 EnumSet.of(State.FORMAL, State.BOUND); 100 101 /** The valid automaton states for a {@link #visitSuperclass} method call. */ 102 private static final EnumSet<State> VISIT_SUPER_CLASS_STATES = 103 EnumSet.of(State.EMPTY, State.FORMAL, State.BOUND); 104 105 /** The valid automaton states for a {@link #visitInterface} method call. */ 106 private static final EnumSet<State> VISIT_INTERFACE_STATES = EnumSet.of(State.SUPER); 107 108 /** The valid automaton states for a {@link #visitParameterType} method call. */ 109 private static final EnumSet<State> VISIT_PARAMETER_TYPE_STATES = 110 EnumSet.of(State.EMPTY, State.FORMAL, State.BOUND, State.PARAM); 111 112 /** The valid automaton states for a {@link #visitReturnType} method call. */ 113 private static final EnumSet<State> VISIT_RETURN_TYPE_STATES = 114 EnumSet.of(State.EMPTY, State.FORMAL, State.BOUND, State.PARAM); 115 116 /** The valid automaton states for a {@link #visitExceptionType} method call. */ 117 private static final EnumSet<State> VISIT_EXCEPTION_TYPE_STATES = EnumSet.of(State.RETURN); 118 119 /** The possible states of the automaton used to check the order of method calls. */ 120 private enum State { 121 EMPTY, 122 FORMAL, 123 BOUND, 124 SUPER, 125 PARAM, 126 RETURN, 127 SIMPLE_TYPE, 128 CLASS_TYPE, 129 END; 130 } 131 132 private static final String INVALID = "Invalid "; 133 134 /** The type of the visited signature. */ 135 private final int type; 136 137 /** The current state of the automaton used to check the order of method calls. */ 138 private State state; 139 140 /** Whether the visited signature can be 'V'. */ 141 private boolean canBeVoid; 142 143 /** The visitor to which this adapter must delegate calls. May be {@literal null}. */ 144 private final SignatureVisitor signatureVisitor; 145 146 /** 147 * Constructs a new {@link CheckSignatureAdapter}. <i>Subclasses must not use this 148 * constructor</i>. Instead, they must use the {@link #CheckSignatureAdapter(int, int, 149 * SignatureVisitor)} version. 150 * 151 * @param type the type of signature to be checked. See {@link #CLASS_SIGNATURE}, {@link 152 * #METHOD_SIGNATURE} and {@link #TYPE_SIGNATURE}. 153 * @param signatureVisitor the visitor to which this adapter must delegate calls. May be {@literal 154 * null}. 155 */ 156 public CheckSignatureAdapter(final int type, final SignatureVisitor signatureVisitor) { 157 this(Opcodes.ASM7, type, signatureVisitor); 158 } 159 160 /** 161 * Constructs a new {@link CheckSignatureAdapter}. 162 * 163 * @param api the ASM API version implemented by this visitor. Must be one of {@link 164 * Opcodes#ASM4}, {@link Opcodes#ASM5}, {@link Opcodes#ASM6} or {@link Opcodes#ASM7}. 165 * @param type the type of signature to be checked. See {@link #CLASS_SIGNATURE}, {@link 166 * #METHOD_SIGNATURE} and {@link #TYPE_SIGNATURE}. 167 * @param signatureVisitor the visitor to which this adapter must delegate calls. May be {@literal 168 * null}. 169 */ 170 protected CheckSignatureAdapter( 171 final int api, final int type, final SignatureVisitor signatureVisitor) { 172 super(api); 173 this.type = type; 174 this.state = State.EMPTY; 175 this.signatureVisitor = signatureVisitor; 176 } 177 178 // class and method signatures 179 180 @Override 181 public void visitFormalTypeParameter(final String name) { 182 if (type == TYPE_SIGNATURE || !VISIT_FORMAL_TYPE_PARAMETER_STATES.contains(state)) { 183 throw new IllegalStateException(); 184 } 185 checkIdentifier(name, "formal type parameter"); 186 state = State.FORMAL; 187 if (signatureVisitor != null) { 188 signatureVisitor.visitFormalTypeParameter(name); 189 } 190 } 191 192 @Override 193 public SignatureVisitor visitClassBound() { 194 if (type == TYPE_SIGNATURE || !VISIT_CLASS_BOUND_STATES.contains(state)) { 195 throw new IllegalStateException(); 196 } 197 state = State.BOUND; 198 return new CheckSignatureAdapter( 199 TYPE_SIGNATURE, signatureVisitor == null ? null : signatureVisitor.visitClassBound()); 200 } 201 202 @Override 203 public SignatureVisitor visitInterfaceBound() { 204 if (type == TYPE_SIGNATURE || !VISIT_INTERFACE_BOUND_STATES.contains(state)) { 205 throw new IllegalArgumentException(); 206 } 207 return new CheckSignatureAdapter( 208 TYPE_SIGNATURE, signatureVisitor == null ? null : signatureVisitor.visitInterfaceBound()); 209 } 210 211 // class signatures 212 213 @Override 214 public SignatureVisitor visitSuperclass() { 215 if (type != CLASS_SIGNATURE || !VISIT_SUPER_CLASS_STATES.contains(state)) { 216 throw new IllegalArgumentException(); 217 } 218 state = State.SUPER; 219 return new CheckSignatureAdapter( 220 TYPE_SIGNATURE, signatureVisitor == null ? null : signatureVisitor.visitSuperclass()); 221 } 222 223 @Override 224 public SignatureVisitor visitInterface() { 225 if (type != CLASS_SIGNATURE || !VISIT_INTERFACE_STATES.contains(state)) { 226 throw new IllegalStateException(); 227 } 228 return new CheckSignatureAdapter( 229 TYPE_SIGNATURE, signatureVisitor == null ? null : signatureVisitor.visitInterface()); 230 } 231 232 // method signatures 233 234 @Override 235 public SignatureVisitor visitParameterType() { 236 if (type != METHOD_SIGNATURE || !VISIT_PARAMETER_TYPE_STATES.contains(state)) { 237 throw new IllegalArgumentException(); 238 } 239 state = State.PARAM; 240 return new CheckSignatureAdapter( 241 TYPE_SIGNATURE, signatureVisitor == null ? null : signatureVisitor.visitParameterType()); 242 } 243 244 @Override 245 public SignatureVisitor visitReturnType() { 246 if (type != METHOD_SIGNATURE || !VISIT_RETURN_TYPE_STATES.contains(state)) { 247 throw new IllegalArgumentException(); 248 } 249 state = State.RETURN; 250 CheckSignatureAdapter checkSignatureAdapter = 251 new CheckSignatureAdapter( 252 TYPE_SIGNATURE, signatureVisitor == null ? null : signatureVisitor.visitReturnType()); 253 checkSignatureAdapter.canBeVoid = true; 254 return checkSignatureAdapter; 255 } 256 257 @Override 258 public SignatureVisitor visitExceptionType() { 259 if (type != METHOD_SIGNATURE || !VISIT_EXCEPTION_TYPE_STATES.contains(state)) { 260 throw new IllegalStateException(); 261 } 262 return new CheckSignatureAdapter( 263 TYPE_SIGNATURE, signatureVisitor == null ? null : signatureVisitor.visitExceptionType()); 264 } 265 266 // type signatures 267 268 @Override 269 public void visitBaseType(final char descriptor) { 270 if (type != TYPE_SIGNATURE || state != State.EMPTY) { 271 throw new IllegalStateException(); 272 } 273 if (descriptor == 'V') { 274 if (!canBeVoid) { 275 throw new IllegalArgumentException(); 276 } 277 } else { 278 if ("ZCBSIFJD".indexOf(descriptor) == -1) { 279 throw new IllegalArgumentException(); 280 } 281 } 282 state = State.SIMPLE_TYPE; 283 if (signatureVisitor != null) { 284 signatureVisitor.visitBaseType(descriptor); 285 } 286 } 287 288 @Override 289 public void visitTypeVariable(final String name) { 290 if (type != TYPE_SIGNATURE || state != State.EMPTY) { 291 throw new IllegalStateException(); 292 } 293 checkIdentifier(name, "type variable"); 294 state = State.SIMPLE_TYPE; 295 if (signatureVisitor != null) { 296 signatureVisitor.visitTypeVariable(name); 297 } 298 } 299 300 @Override 301 public SignatureVisitor visitArrayType() { 302 if (type != TYPE_SIGNATURE || state != State.EMPTY) { 303 throw new IllegalStateException(); 304 } 305 state = State.SIMPLE_TYPE; 306 return new CheckSignatureAdapter( 307 TYPE_SIGNATURE, signatureVisitor == null ? null : signatureVisitor.visitArrayType()); 308 } 309 310 @Override 311 public void visitClassType(final String name) { 312 if (type != TYPE_SIGNATURE || state != State.EMPTY) { 313 throw new IllegalStateException(); 314 } 315 checkClassName(name, "class name"); 316 state = State.CLASS_TYPE; 317 if (signatureVisitor != null) { 318 signatureVisitor.visitClassType(name); 319 } 320 } 321 322 @Override 323 public void visitInnerClassType(final String name) { 324 if (state != State.CLASS_TYPE) { 325 throw new IllegalStateException(); 326 } 327 checkIdentifier(name, "inner class name"); 328 if (signatureVisitor != null) { 329 signatureVisitor.visitInnerClassType(name); 330 } 331 } 332 333 @Override 334 public void visitTypeArgument() { 335 if (state != State.CLASS_TYPE) { 336 throw new IllegalStateException(); 337 } 338 if (signatureVisitor != null) { 339 signatureVisitor.visitTypeArgument(); 340 } 341 } 342 343 @Override 344 public SignatureVisitor visitTypeArgument(final char wildcard) { 345 if (state != State.CLASS_TYPE) { 346 throw new IllegalStateException(); 347 } 348 if ("+-=".indexOf(wildcard) == -1) { 349 throw new IllegalArgumentException(); 350 } 351 return new CheckSignatureAdapter( 352 TYPE_SIGNATURE, 353 signatureVisitor == null ? null : signatureVisitor.visitTypeArgument(wildcard)); 354 } 355 356 @Override 357 public void visitEnd() { 358 if (state != State.CLASS_TYPE) { 359 throw new IllegalStateException(); 360 } 361 state = State.END; 362 if (signatureVisitor != null) { 363 signatureVisitor.visitEnd(); 364 } 365 } 366 367 private void checkClassName(final String name, final String message) { 368 if (name == null || name.length() == 0) { 369 throw new IllegalArgumentException(INVALID + message + " (must not be null or empty)"); 370 } 371 for (int i = 0; i < name.length(); ++i) { 372 if (".;[<>:".indexOf(name.charAt(i)) != -1) { 373 throw new IllegalArgumentException( 374 INVALID + message + " (must not contain . ; [ < > or :): " + name); 375 } 376 } 377 } 378 379 private void checkIdentifier(final String name, final String message) { 380 if (name == null || name.length() == 0) { 381 throw new IllegalArgumentException(INVALID + message + " (must not be null or empty)"); 382 } 383 for (int i = 0; i < name.length(); ++i) { 384 if (".;[/<>:".indexOf(name.charAt(i)) != -1) { 385 throw new IllegalArgumentException( 386 INVALID + message + " (must not contain . ; [ / < > or :): " + name); 387 } 388 } 389 } 390 }