WALA/com.ibm.wala.core/src/com/ibm/wala/util/Exceptions.java

343 lines
12 KiB
Java

/*******************************************************************************
* Copyright (c) 2002 - 2006 IBM Corporation.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package com.ibm.wala.util;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import com.ibm.wala.classLoader.IClass;
import com.ibm.wala.classLoader.IMethod;
import com.ibm.wala.ipa.cha.ClassHierarchy;
import com.ibm.wala.shrikeBT.ConstantInstruction;
import com.ibm.wala.shrikeBT.Constants;
import com.ibm.wala.shrikeBT.Instruction;
import com.ibm.wala.shrikeBT.InvokeInstruction;
import com.ibm.wala.shrikeCT.InvalidClassFileException;
import com.ibm.wala.types.ClassLoaderReference;
import com.ibm.wala.types.MemberReference;
import com.ibm.wala.types.MethodReference;
import com.ibm.wala.types.TypeReference;
import com.ibm.wala.util.debug.Assertions;
import com.ibm.wala.util.warnings.Warning;
import com.ibm.wala.util.warnings.WarningSet;
/**
*
* Utility class to help deal with analysis of exceptions.
*
* @author sfink
*/
public class Exceptions implements Constants {
private static final Collection<TypeReference> arrayAccessExceptions = Collections.unmodifiableCollection(Arrays.asList(new TypeReference[] {
TypeReference.JavaLangNullPointerException, TypeReference.JavaLangArrayIndexOutOfBoundsException }));;
private static final Collection<TypeReference> aaStoreExceptions = Collections.unmodifiableCollection(Arrays.asList(new TypeReference[] {
TypeReference.JavaLangNullPointerException, TypeReference.JavaLangArrayIndexOutOfBoundsException,
TypeReference.JavaLangArrayStoreException }));
private static final Collection<TypeReference> newScalarExceptions = Collections.unmodifiableCollection(Arrays.asList(new TypeReference[] {
TypeReference.JavaLangExceptionInInitializerError, TypeReference.JavaLangOutOfMemoryError }));
private static final Collection<TypeReference> newArrayExceptions = Collections.unmodifiableCollection(Arrays.asList(new TypeReference[] {
TypeReference.JavaLangOutOfMemoryError, TypeReference.JavaLangNegativeArraySizeException }));
private static final Collection<TypeReference> nullPointerException = Collections.singleton(TypeReference.JavaLangNullPointerException);
private static final Collection<TypeReference> arithmeticException = Collections.singleton(TypeReference.JavaLangArithmeticException);
private static final Collection<TypeReference> classCastException = Collections.singleton(TypeReference.JavaLangClassCastException);
private static final Collection<TypeReference> classNotFoundException = Collections.singleton(TypeReference.JavaLangClassNotFoundException);
private static final Collection<TypeReference> runtimeExceptions = Collections.unmodifiableCollection(Arrays.asList(new TypeReference[] {
TypeReference.JavaLangArithmeticException, TypeReference.JavaLangArrayStoreException,
TypeReference.JavaLangClassCastException, TypeReference.JavaLangArrayIndexOutOfBoundsException,
TypeReference.JavaLangNegativeArraySizeException, TypeReference.JavaLangNullPointerException }));;
/**
* @param pei
* a potentially-excepting insruction
* @param cha
* the governing class hierarchy
* @return the exception types that pei may throw
*
* Notes
* <ul>
* <li>this method does not handle athrow instructions
* <li>this method ignores OutOfMemoryError
* <li>this method ignores linkage errors
* <li>this method ignores IllegalMonitorState exceptions
* </ul>
* @throws IllegalArgumentException if pei is null
*
*/
public static Collection<TypeReference> getExceptionTypes(ClassLoaderReference loader, Instruction pei, ClassHierarchy cha, WarningSet warnings) {
if (pei == null) {
throw new IllegalArgumentException("pei is null");
}
switch (pei.getOpcode()) {
case OP_invokevirtual:
case OP_invokespecial:
case OP_invokestatic:
case OP_invokeinterface:
InvokeInstruction call = (InvokeInstruction) pei;
Collection<TypeReference> result = null;
try {
result = inferInvokeExceptions(MethodReference.findOrCreate(loader, call.getClassType(), call.getMethodName(),
call.getMethodSignature()), cha, warnings);
} catch (InvalidClassFileException e) {
e.printStackTrace();
Assertions.UNREACHABLE();
}
return result;
case OP_athrow:
Assertions.UNREACHABLE("This class does not have the smarts to infer exception types for athrow");
return null;
default:
return getIndependentExceptionTypes(pei);
}
}
/**
* @return Colection<TypeReference>, set of exception types a call to a
* declared target might throw.
* @throws InvalidClassFileException
* @throws IllegalArgumentException if target is null
* @throws IllegalArgumentException if cha is null
*/
public static Collection<TypeReference> inferInvokeExceptions(MethodReference target, ClassHierarchy cha, WarningSet warnings) throws InvalidClassFileException {
if (cha == null) {
throw new IllegalArgumentException("cha is null");
}
if (target == null) {
throw new IllegalArgumentException("target is null");
}
ArrayList<TypeReference> set = new ArrayList<TypeReference>(runtimeExceptions);
set.addAll(cha.getJavaLangErrorTypes());
IClass klass = cha.lookupClass(target.getDeclaringClass());
if (klass == null) {
warnings.add(MethodResolutionFailure.moderate(target));
}
if (klass != null) {
IMethod M = klass.getMethod(target.getSelector());
if (M == null) {
warnings.add(MethodResolutionFailure.severe(target));
} else {
TypeReference[] exceptionTypes = M.getDeclaredExceptions();
if (exceptionTypes != null) {
set.addAll(Arrays.asList(exceptionTypes));
}
}
}
return set;
}
/**
* @author sfink
*
* A warning for when we fail to resolve the type for a checkcast
*/
private static class MethodResolutionFailure extends Warning {
final MemberReference method;
MethodResolutionFailure(byte code, MemberReference method) {
super(code);
this.method = method;
}
@Override
public String getMsg() {
return getClass().toString() + " : " + method;
}
public static MethodResolutionFailure moderate(MemberReference method) {
return new MethodResolutionFailure(Warning.MODERATE, method);
}
public static MethodResolutionFailure severe(MemberReference method) {
return new MethodResolutionFailure(Warning.SEVERE, method);
}
}
/**
* @param pei
* a potentially-excepting insruction
* @return the exception types that pei may throw, independent of the class
* hierarchy
*
* Notes
* <ul>
* <li>this method will <em>NOT</em> return the exception type explicitly
* thrown by an athrow
* <li>this method will <em>NOT</em> return the exception types that a
* called method may throw
* <li>this method ignores OutOfMemoryError
* <li>this method ignores linkage errors
* <li>this method ignores IllegalMonitorState exceptions
* </ul>
*
* TODO: move this elsewhere.
* @throws IllegalArgumentException if pei is null
*/
public static Collection<TypeReference> getIndependentExceptionTypes(Instruction pei) {
if (pei == null) {
throw new IllegalArgumentException("pei is null");
}
switch (pei.getOpcode()) {
case OP_iaload:
case OP_laload:
case OP_faload:
case OP_daload:
case OP_aaload:
case OP_baload:
case OP_caload:
case OP_saload:
case OP_iastore:
case OP_lastore:
case OP_fastore:
case OP_dastore:
case OP_bastore:
case OP_castore:
case OP_sastore:
return getArrayAccessExceptions();
case OP_aastore:
return getAaStoreExceptions();
case OP_getfield:
case OP_putfield:
case OP_invokevirtual:
case OP_invokespecial:
case OP_invokestatic:
case OP_invokeinterface:
return getNullPointerException();
case OP_idiv:
return getArithmeticException();
case OP_new:
return newScalarExceptions;
case OP_newarray:
case OP_anewarray:
case OP_multianewarray:
return newArrayExceptions;
case OP_arraylength:
return getNullPointerException();
case OP_athrow:
// N.B: the caller must handle the explicitly-thrown exception
return getNullPointerException();
case OP_checkcast:
return getClassCastException();
case OP_monitorenter:
case OP_monitorexit:
// we're currently ignoring MonitorStateExceptions, since J2EE stuff
// should be
// logically single-threaded
return getNullPointerException();
case OP_ldc_w:
if (((ConstantInstruction) pei).getType().equals(TYPE_Class))
return getClassNotFoundException();
else
return null;
default:
return null;
}
}
/**
* TODO: move this elsewhere. Move it into shrike and develop new way to track
* peis.
* @throws IllegalArgumentException if s is null
*/
public static boolean isPEI(Instruction s) {
if (s == null) {
throw new IllegalArgumentException("s is null");
}
switch (s.getOpcode()) {
case OP_iaload:
case OP_laload:
case OP_faload:
case OP_daload:
case OP_aaload:
case OP_baload:
case OP_caload:
case OP_saload:
case OP_iastore:
case OP_lastore:
case OP_fastore:
case OP_dastore:
case OP_aastore:
case OP_bastore:
case OP_castore:
case OP_sastore:
case OP_getfield:
case OP_putfield:
case OP_idiv:
case OP_invokevirtual:
case OP_invokespecial:
case OP_invokestatic:
case OP_invokeinterface:
case OP_new:
case OP_newarray:
case OP_anewarray:
case OP_arraylength:
case OP_athrow:
case OP_checkcast:
case OP_monitorenter:
case OP_monitorexit:
case OP_multianewarray:
return true;
case OP_ldc_w:
return (((ConstantInstruction) s).getType().equals(TYPE_Class));
default:
return false;
}
}
public static Collection<TypeReference> getAaStoreExceptions() {
return aaStoreExceptions;
}
public static Collection<TypeReference> getArithmeticException() {
return arithmeticException;
}
public static Collection<TypeReference> getArrayAccessExceptions() {
return arrayAccessExceptions;
}
public static Collection<TypeReference> getClassCastException() {
return classCastException;
}
public static Collection<TypeReference> getClassNotFoundException() {
return classNotFoundException;
}
public static Collection<TypeReference> getNewArrayExceptions() {
return newArrayExceptions;
}
public static Collection<TypeReference> getNewScalarExceptions() {
return newScalarExceptions;
}
public static Collection<TypeReference> getNullPointerException() {
return nullPointerException;
}
public static Collection<TypeReference> getRuntimeExceptions() {
return runtimeExceptions;
}
}