View Javadoc

    1   /*
    2    * Copyright  2000-2004 The Apache Software Foundation
    3    *
    4    *  Licensed under the Apache License, Version 2.0 (the "License");
    5    *  you may not use this file except in compliance with the License.
    6    *  You may obtain a copy of the License at
    7    *
    8    *      http://www.apache.org/licenses/LICENSE-2.0
    9    *
    10   *  Unless required by applicable law or agreed to in writing, software
    11   *  distributed under the License is distributed on an "AS IS" BASIS,
    12   *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13   *  See the License for the specific language governing permissions and
    14   *  limitations under the License.
    15   *
    16   */
    17  package org.apache.bcel.verifier.structurals;
    18
    19
    20  import org.apache.bcel.generic.ReferenceType;
    21  import org.apache.bcel.generic.Type;
    22  import org.apache.bcel.verifier.exc.AssertionViolatedException;
    23  import org.apache.bcel.verifier.exc.StructuralCodeConstraintException;
    24
    25  /***
    26   * This class implements an array of local variables used for symbolic JVM
    27   * simulation.
    28   *
    29   * @version $Id: LocalVariables.java 386056 2006-03-15 11:31:56Z tcurdt $
    30   * @author Enver Haase
    31   */
    32  public class LocalVariables{
    33  	/*** The Type[] containing the local variable slots. */
    34  	private Type[] locals;
    35
    36  	/***
    37  	 * Creates a new LocalVariables object.
    38  	 */
    39  	public LocalVariables(int maxLocals){
    40  		locals = new Type[maxLocals];
    41  		for (int i=0; i<maxLocals; i++){
    42  			locals[i] = Type.UNKNOWN;
    43  		}
    44  	}
    45
    46  	/***
    47  	 * Returns a deep copy of this object; i.e. the clone
    48  	 * operates on a new local variable array.
    49  	 * However, the Type objects in the array are shared.
    50  	 */
    51  	protected Object clone(){
    52  		LocalVariables lvs = new LocalVariables(locals.length);
    53  		for (int i=0; i<locals.length; i++){
    54  			lvs.locals[i] = this.locals[i];
    55  		}
    56  		return lvs;
    57  	}
    58
    59  	/***
    60  	 * Returns the type of the local variable slot i.
    61  	 */
    62  	public Type get(int i){
    63  		return locals[i];
    64  	}
    65
    66  	/***
    67  	 * Returns a (correctly typed) clone of this object.
    68  	 * This is equivalent to ((LocalVariables) this.clone()).
    69  	 */
    70  	public LocalVariables getClone(){
    71  		return (LocalVariables) this.clone();
    72  	}
    73
    74  	/***
    75  	 * Returns the number of local variable slots this
    76  	 * LocalVariables instance has.
    77  	 */
    78  	public int maxLocals(){
    79  		return locals.length;
    80  	}
    81
    82  	/***
    83  	 * Sets a new Type for the given local variable slot.
    84  	 */
    85  	public void set(int i, Type type){
    86  		if (type == Type.BYTE || type == Type.SHORT || type == Type.BOOLEAN || type == Type.CHAR){
    87  			throw new AssertionViolatedException("LocalVariables do not know about '"+type+"'. Use Type.INT instead.");
    88  		}
    89  		locals[i] = type;
    90  	}
    91
    92  	/*** @return a hash code value for the object.
    93       */
    94  	public int hashCode() { return locals.length; }
    95
    96  	/*
    97  	 * Fulfills the general contract of Object.equals().
    98  	 */
    99  	public boolean equals(Object o){
    100 		if (!(o instanceof LocalVariables)) {
    101             return false;
    102         }
    103 		LocalVariables lv = (LocalVariables) o;
    104 		if (this.locals.length != lv.locals.length) {
    105             return false;
    106         }
    107 		for (int i=0; i<this.locals.length; i++){
    108 			if (!this.locals[i].equals(lv.locals[i])){
    109 				//System.out.println(this.locals[i]+" is not "+lv.locals[i]);
    110 				return false;
    111 			}
    112 		}
    113 		return true;
    114 	}
    115
    116 	/***
    117 	 * Merges two local variables sets as described in the Java Virtual Machine Specification,
    118 	 * Second Edition, section 4.9.2, page 146.
    119 	 */
    120 	public void merge(LocalVariables lv){
    121
    122 		if (this.locals.length != lv.locals.length){
    123 			throw new AssertionViolatedException("Merging LocalVariables of different size?!? From different methods or what?!?");
    124 		}
    125
    126 		for (int i=0; i<locals.length; i++){
    127 			merge(lv, i);
    128 		}
    129 	}
    130
    131 	/***
    132 	 * Merges a single local variable.
    133 	 *
    134 	 * @see #merge(LocalVariables)
    135 	 */
    136 	private void merge(LocalVariables lv, int i){
    137 	    try {
    138
    139 		// We won't accept an unitialized object if we know it was initialized;
    140 		// compare vmspec2, 4.9.4, last paragraph.
    141 		if ( (!(locals[i] instanceof UninitializedObjectType)) && (lv.locals[i] instanceof UninitializedObjectType) ){
    142 			throw new StructuralCodeConstraintException("Backwards branch with an uninitialized object in the local variables detected.");
    143 		}
    144 		// Even harder, what about _different_ uninitialized object types?!
    145 		if ( (!(locals[i].equals(lv.locals[i]))) && (locals[i] instanceof UninitializedObjectType) && (lv.locals[i] instanceof UninitializedObjectType) ){
    146 			throw new StructuralCodeConstraintException("Backwards branch with an uninitialized object in the local variables detected.");
    147 		}
    148 		// If we just didn't know that it was initialized, we have now learned.
    149 		if (locals[i] instanceof UninitializedObjectType){
    150 			if (! (lv.locals[i] instanceof UninitializedObjectType)){
    151 				locals[i] = ((UninitializedObjectType) locals[i]).getInitialized();
    152 			}
    153 		}
    154 		if ((locals[i] instanceof ReferenceType) && (lv.locals[i] instanceof ReferenceType)){
    155 			if (! locals[i].equals(lv.locals[i])){ // needed in case of two UninitializedObjectType instances
    156 				Type sup = ((ReferenceType) locals[i]).getFirstCommonSuperclass((ReferenceType) (lv.locals[i]));
    157
    158 				if (sup != null){
    159 					locals[i] = sup;
    160 				}
    161 				else{
    162 					// We should have checked this in Pass2!
    163 					throw new AssertionViolatedException("Could not load all the super classes of '"+locals[i]+"' and '"+lv.locals[i]+"'.");
    164 				}
    165 			}
    166 		}
    167 		else{
    168 			if (! (locals[i].equals(lv.locals[i])) ){
    169 /*TODO
    170 				if ((locals[i] instanceof org.apache.bcel.generic.ReturnaddressType) && (lv.locals[i] instanceof org.apache.bcel.generic.ReturnaddressType)){
    171 					//System.err.println("merging "+locals[i]+" and "+lv.locals[i]);
    172 					throw new AssertionViolatedException("Merging different ReturnAddresses: '"+locals[i]+"' and '"+lv.locals[i]+"'.");
    173 				}
    174 */
    175 				locals[i] = Type.UNKNOWN;
    176 			}
    177 		}
    178 	    } catch (ClassNotFoundException e) {
    179 		// FIXME: maybe not the best way to handle this
    180 		throw new AssertionViolatedException("Missing class: " + e.toString());
    181 	    }
    182 	}
    183
    184 	/***
    185 	 * Returns a String representation of this object.
    186 	 */
    187 	public String toString(){
    188 		StringBuffer sb = new StringBuffer();
    189 		for (int i=0; i<locals.length; i++){
    190 			sb.append(Integer.toString(i));
    191 			sb.append(": ");
    192 			sb.append(locals[i]);
    193 			sb.append("\n");
    194 		}
    195 		return sb.toString();
    196 	}
    197
    198 	/***
    199 	 * Replaces all occurences of u in this local variables set
    200 	 * with an "initialized" ObjectType.
    201 	 */
    202 	public void initializeObject(UninitializedObjectType u){
    203 		for (int i=0; i<locals.length; i++){
    204 			if (locals[i] == u){
    205 				locals[i] = u.getInitialized();
    206 			}
    207 		}
    208 	}
    209 }