package soot.toolkits.exceptions; import soot.*; import java.util.*; /** * Class which packages together some objects useful in * unit tests of exception handling. */ public class ExceptionTestUtility { // Individual Throwable types for our tests: final RefType THROWABLE; final RefType EXCEPTION; final RefType RUNTIME_EXCEPTION; final RefType ARITHMETIC_EXCEPTION; final RefType ARRAY_STORE_EXCEPTION; final RefType CLASS_CAST_EXCEPTION ; final RefType ILLEGAL_MONITOR_STATE_EXCEPTION; final RefType INDEX_OUT_OF_BOUNDS_EXCEPTION; final RefType ARRAY_INDEX_OUT_OF_BOUNDS_EXCEPTION; final RefType STRING_INDEX_OUT_OF_BOUNDS_EXCEPTION; final RefType NEGATIVE_ARRAY_SIZE_EXCEPTION; final RefType NULL_POINTER_EXCEPTION; final RefType ERROR; final RefType LINKAGE_ERROR; final RefType CLASS_CIRCULARITY_ERROR; final RefType CLASS_FORMAT_ERROR; final RefType UNSUPPORTED_CLASS_VERSION_ERROR; final RefType EXCEPTION_IN_INITIALIZER_ERROR; final RefType INCOMPATIBLE_CLASS_CHANGE_ERROR; final RefType ABSTRACT_METHOD_ERROR; final RefType ILLEGAL_ACCESS_ERROR; final RefType INSTANTIATION_ERROR; final RefType NO_SUCH_FIELD_ERROR; final RefType NO_SUCH_METHOD_ERROR; final RefType NO_CLASS_DEF_FOUND_ERROR; final RefType UNSATISFIED_LINK_ERROR; final RefType VERIFY_ERROR; final RefType THREAD_DEATH; final RefType VIRTUAL_MACHINE_ERROR; final RefType INTERNAL_ERROR; final RefType OUT_OF_MEMORY_ERROR; final RefType STACK_OVERFLOW_ERROR; final RefType UNKNOWN_ERROR; final RefType AWT_ERROR; final RefType UNDECLARED_THROWABLE_EXCEPTION; final RefType UNSUPPORTED_LOOK_AND_FEEL_EXCEPTION; // The universe of all Throwable types for our tests: final Set ALL_TEST_THROWABLES; // Set that matches the representation of all Throwables used // internally by ThrowableSet: final Set ALL_THROWABLES_REP; // Some useful subsets of our Throwable universe: final Set VM_ERRORS; final Set VM_ERRORS_PLUS_SUPERTYPES; final Set VM_AND_RESOLVE_CLASS_ERRORS; final Set VM_AND_RESOLVE_CLASS_ERRORS_PLUS_SUPERTYPES; final Set VM_AND_RESOLVE_FIELD_ERRORS; final Set VM_AND_RESOLVE_FIELD_ERRORS_PLUS_SUPERTYPES; final Set VM_AND_RESOLVE_METHOD_ERRORS; final Set VM_AND_RESOLVE_METHOD_ERRORS_PLUS_SUPERTYPES; final Set ALL_TEST_ERRORS; final Set ALL_TEST_ERRORS_PLUS_SUPERTYPES; final Set PERENNIAL_THROW_EXCEPTIONS; final Set PERENNIAL_THROW_EXCEPTIONS_PLUS_SUPERTYPES; final Set THROW_PLUS_INCOMPATIBLE_CLASS_CHANGE; final Set THROW_PLUS_INCOMPATIBLE_CLASS_CHANGE_PLUS_SUPERTYPES; final Set THROW_PLUS_INCOMPATIBLE_CLASS_CHANGE_PLUS_SUBTYPES; final Set THROW_PLUS_INCOMPATIBLE_CLASS_CHANGE_PLUS_SUBTYPES_PLUS_SUPERTYPES; // Sets that match the representations of subsets of Errors used // internally by ThrowableSet: final Set VM_AND_RESOLVE_CLASS_ERRORS_REP; final Set VM_AND_RESOLVE_FIELD_ERRORS_REP; final Set VM_AND_RESOLVE_METHOD_ERRORS_REP; final Set ALL_ERRORS_REP; ExceptionTestUtility(String pathToJavaLib) { Scene.v().setSootClassPath(pathToJavaLib); THROWABLE = Scene.v().getRefType("java.lang.Throwable"); ERROR = Scene.v().getRefType("java.lang.Error"); Scene.v().loadClassAndSupport("java.lang.Exception"); EXCEPTION = Scene.v().getRefType("java.lang.Exception"); // runtime exceptions. RUNTIME_EXCEPTION = Scene.v().getRefType("java.lang.RuntimeException"); ARITHMETIC_EXCEPTION = Scene.v().getRefType("java.lang.ArithmeticException"); ARRAY_STORE_EXCEPTION = Scene.v().getRefType("java.lang.ArrayStoreException"); CLASS_CAST_EXCEPTION = Scene.v().getRefType("java.lang.ClassCastException"); ILLEGAL_MONITOR_STATE_EXCEPTION = Scene.v().getRefType("java.lang.IllegalMonitorStateException"); INDEX_OUT_OF_BOUNDS_EXCEPTION = Scene.v().getRefType("java.lang.IndexOutOfBoundsException"); ARRAY_INDEX_OUT_OF_BOUNDS_EXCEPTION = Scene.v().getRefType("java.lang.ArrayIndexOutOfBoundsException"); Scene.v().loadClassAndSupport("java.lang.StringIndexOutOfBoundsException"); STRING_INDEX_OUT_OF_BOUNDS_EXCEPTION = Scene.v().getRefType("java.lang.StringIndexOutOfBoundsException"); NEGATIVE_ARRAY_SIZE_EXCEPTION = Scene.v().getRefType("java.lang.NegativeArraySizeException"); NULL_POINTER_EXCEPTION = Scene.v().getRefType("java.lang.NullPointerException"); // linkage errors. LINKAGE_ERROR = Scene.v().getRefType("java.lang.LinkageError"); CLASS_CIRCULARITY_ERROR = Scene.v().getRefType("java.lang.ClassCircularityError"); CLASS_FORMAT_ERROR = Scene.v().getRefType("java.lang.ClassFormatError"); Scene.v().loadClassAndSupport("java.lang.UnsupportedClassVersionError"); UNSUPPORTED_CLASS_VERSION_ERROR = Scene.v().getRefType("java.lang.UnsupportedClassVersionError"); EXCEPTION_IN_INITIALIZER_ERROR = Scene.v().getRefType("java.lang.ExceptionInInitializerError"); INCOMPATIBLE_CLASS_CHANGE_ERROR = Scene.v().getRefType("java.lang.IncompatibleClassChangeError"); ABSTRACT_METHOD_ERROR = Scene.v().getRefType("java.lang.AbstractMethodError"); ILLEGAL_ACCESS_ERROR = Scene.v().getRefType("java.lang.IllegalAccessError"); INSTANTIATION_ERROR = Scene.v().getRefType("java.lang.InstantiationError"); NO_SUCH_FIELD_ERROR = Scene.v().getRefType("java.lang.NoSuchFieldError"); NO_SUCH_METHOD_ERROR = Scene.v().getRefType("java.lang.NoSuchMethodError"); NO_CLASS_DEF_FOUND_ERROR = Scene.v().getRefType("java.lang.NoClassDefFoundError"); UNSATISFIED_LINK_ERROR = Scene.v().getRefType("java.lang.UnsatisfiedLinkError"); VERIFY_ERROR = Scene.v().getRefType("java.lang.VerifyError"); // Token non-linkage Error (in the sense that it is not among // Errors that the VM might throw itself during linkage---any // error could be generated during linking by a static // initializer). Scene.v().loadClassAndSupport("java.awt.AWTError"); AWT_ERROR = Scene.v().getRefType("java.awt.AWTError"); // VM errors: INTERNAL_ERROR = Scene.v().getRefType("java.lang.InternalError"); OUT_OF_MEMORY_ERROR = Scene.v().getRefType("java.lang.OutOfMemoryError"); STACK_OVERFLOW_ERROR = Scene.v().getRefType("java.lang.StackOverflowError"); UNKNOWN_ERROR = Scene.v().getRefType("java.lang.UnknownError"); THREAD_DEATH = Scene.v().getRefType("java.lang.ThreadDeath"); Scene.v().loadClassAndSupport("java.lang.VirtualMachineError"); VIRTUAL_MACHINE_ERROR = Scene.v().getRefType("java.lang.VirtualMachineError"); // Two Throwables that our test statements will never throw (except // for invoke statements--in the absence of interprocedural analysis, // we have to assume they can throw anything). Scene.v().loadClassAndSupport("java.lang.reflect.UndeclaredThrowableException"); UNDECLARED_THROWABLE_EXCEPTION = Scene.v().getRefType("java.lang.reflect.UndeclaredThrowableException"); Scene.v().loadClassAndSupport("javax.swing.UnsupportedLookAndFeelException"); UNSUPPORTED_LOOK_AND_FEEL_EXCEPTION = Scene.v().getRefType("javax.swing.UnsupportedLookAndFeelException"); VM_ERRORS = Collections.unmodifiableSet( new ExceptionHashSet(Arrays.asList(new RefType[] { THREAD_DEATH, INTERNAL_ERROR, OUT_OF_MEMORY_ERROR, STACK_OVERFLOW_ERROR, UNKNOWN_ERROR, }))); Set temp = new ExceptionHashSet(VM_ERRORS); temp.add(VIRTUAL_MACHINE_ERROR); temp.add(ERROR); temp.add(THROWABLE); VM_ERRORS_PLUS_SUPERTYPES = Collections.unmodifiableSet(temp); temp = new ExceptionHashSet(VM_ERRORS); temp.add(CLASS_CIRCULARITY_ERROR); temp.add(ILLEGAL_ACCESS_ERROR); temp.add(INCOMPATIBLE_CLASS_CHANGE_ERROR); temp.add(LINKAGE_ERROR); temp.add(NO_CLASS_DEF_FOUND_ERROR); temp.add(VERIFY_ERROR); Set tempForRep = new ExceptionHashSet(temp); tempForRep.add(AnySubType.v(CLASS_FORMAT_ERROR)); VM_AND_RESOLVE_CLASS_ERRORS_REP = Collections.unmodifiableSet(tempForRep); temp.add(CLASS_FORMAT_ERROR); temp.add(UNSUPPORTED_CLASS_VERSION_ERROR); VM_AND_RESOLVE_CLASS_ERRORS = Collections.unmodifiableSet(temp); temp.add(VIRTUAL_MACHINE_ERROR); temp.add(ERROR); temp.add(THROWABLE); VM_AND_RESOLVE_CLASS_ERRORS_PLUS_SUPERTYPES = Collections.unmodifiableSet(temp); temp = new ExceptionHashSet(VM_AND_RESOLVE_CLASS_ERRORS_REP); temp.add(NO_SUCH_FIELD_ERROR); VM_AND_RESOLVE_FIELD_ERRORS_REP = Collections.unmodifiableSet(temp); temp = new ExceptionHashSet(VM_AND_RESOLVE_CLASS_ERRORS); temp.add(NO_SUCH_FIELD_ERROR); VM_AND_RESOLVE_FIELD_ERRORS = Collections.unmodifiableSet(temp); temp.add(VIRTUAL_MACHINE_ERROR); temp.add(ERROR); temp.add(THROWABLE); VM_AND_RESOLVE_FIELD_ERRORS_PLUS_SUPERTYPES = Collections.unmodifiableSet(temp); temp = new ExceptionHashSet(VM_AND_RESOLVE_CLASS_ERRORS_REP); temp.add(ABSTRACT_METHOD_ERROR); temp.add(NO_SUCH_METHOD_ERROR); temp.add(UNSATISFIED_LINK_ERROR); VM_AND_RESOLVE_METHOD_ERRORS_REP = Collections.unmodifiableSet(temp); temp = new ExceptionHashSet(VM_AND_RESOLVE_CLASS_ERRORS); temp.add(ABSTRACT_METHOD_ERROR); temp.add(NO_SUCH_METHOD_ERROR); temp.add(UNSATISFIED_LINK_ERROR); VM_AND_RESOLVE_METHOD_ERRORS = Collections.unmodifiableSet(temp); temp.add(VIRTUAL_MACHINE_ERROR); temp.add(ERROR); temp.add(THROWABLE); VM_AND_RESOLVE_METHOD_ERRORS_PLUS_SUPERTYPES = Collections.unmodifiableSet(temp); temp = new ExceptionHashSet(); temp.add(AnySubType.v(Scene.v().getRefType("java.lang.Error"))); ALL_ERRORS_REP = Collections.unmodifiableSet(temp); temp = new ExceptionHashSet(VM_AND_RESOLVE_METHOD_ERRORS); temp.add(NO_SUCH_FIELD_ERROR); temp.add(EXCEPTION_IN_INITIALIZER_ERROR); temp.add(INSTANTIATION_ERROR); temp.add(AWT_ERROR); ALL_TEST_ERRORS = Collections.unmodifiableSet(temp); temp = new ExceptionHashSet(ALL_TEST_ERRORS); temp.add(VIRTUAL_MACHINE_ERROR); temp.add(ERROR); temp.add(THROWABLE); ALL_TEST_ERRORS_PLUS_SUPERTYPES = Collections.unmodifiableSet(temp); temp = new ExceptionHashSet(VM_ERRORS); temp.add(ILLEGAL_MONITOR_STATE_EXCEPTION); temp.add(NULL_POINTER_EXCEPTION); PERENNIAL_THROW_EXCEPTIONS = Collections.unmodifiableSet(temp); temp = new ExceptionHashSet(VM_ERRORS_PLUS_SUPERTYPES); temp.add(ILLEGAL_MONITOR_STATE_EXCEPTION); temp.add(NULL_POINTER_EXCEPTION); temp.add(RUNTIME_EXCEPTION); temp.add(EXCEPTION); PERENNIAL_THROW_EXCEPTIONS_PLUS_SUPERTYPES = Collections.unmodifiableSet(temp); temp = new ExceptionHashSet(PERENNIAL_THROW_EXCEPTIONS); temp.add(INCOMPATIBLE_CLASS_CHANGE_ERROR); THROW_PLUS_INCOMPATIBLE_CLASS_CHANGE = Collections.unmodifiableSet(temp); temp = new ExceptionHashSet(PERENNIAL_THROW_EXCEPTIONS_PLUS_SUPERTYPES); temp.add(INCOMPATIBLE_CLASS_CHANGE_ERROR); temp.add(LINKAGE_ERROR); THROW_PLUS_INCOMPATIBLE_CLASS_CHANGE_PLUS_SUPERTYPES = Collections.unmodifiableSet(temp); temp = new ExceptionHashSet(THROW_PLUS_INCOMPATIBLE_CLASS_CHANGE); temp.add(ABSTRACT_METHOD_ERROR); temp.add(ILLEGAL_ACCESS_ERROR); temp.add(INSTANTIATION_ERROR);; temp.add(NO_SUCH_FIELD_ERROR); temp.add(NO_SUCH_METHOD_ERROR); THROW_PLUS_INCOMPATIBLE_CLASS_CHANGE_PLUS_SUBTYPES = Collections.unmodifiableSet(temp); temp = new ExceptionHashSet(THROW_PLUS_INCOMPATIBLE_CLASS_CHANGE_PLUS_SUPERTYPES); temp.add(ABSTRACT_METHOD_ERROR); temp.add(ILLEGAL_ACCESS_ERROR); temp.add(INSTANTIATION_ERROR);; temp.add(NO_SUCH_FIELD_ERROR); temp.add(NO_SUCH_METHOD_ERROR); THROW_PLUS_INCOMPATIBLE_CLASS_CHANGE_PLUS_SUBTYPES_PLUS_SUPERTYPES = Collections.unmodifiableSet(temp); temp = new ExceptionHashSet(Arrays.asList(new RefType[] { THROWABLE, EXCEPTION, RUNTIME_EXCEPTION, ARITHMETIC_EXCEPTION, ARRAY_STORE_EXCEPTION, CLASS_CAST_EXCEPTION , ILLEGAL_MONITOR_STATE_EXCEPTION, INDEX_OUT_OF_BOUNDS_EXCEPTION, ARRAY_INDEX_OUT_OF_BOUNDS_EXCEPTION, STRING_INDEX_OUT_OF_BOUNDS_EXCEPTION, NEGATIVE_ARRAY_SIZE_EXCEPTION, NULL_POINTER_EXCEPTION, ERROR, LINKAGE_ERROR, CLASS_CIRCULARITY_ERROR, CLASS_FORMAT_ERROR, UNSUPPORTED_CLASS_VERSION_ERROR, EXCEPTION_IN_INITIALIZER_ERROR, INCOMPATIBLE_CLASS_CHANGE_ERROR, ABSTRACT_METHOD_ERROR, ILLEGAL_ACCESS_ERROR, INSTANTIATION_ERROR, NO_SUCH_FIELD_ERROR, NO_SUCH_METHOD_ERROR, NO_CLASS_DEF_FOUND_ERROR, UNSATISFIED_LINK_ERROR, VERIFY_ERROR, THREAD_DEATH, VIRTUAL_MACHINE_ERROR, INTERNAL_ERROR, OUT_OF_MEMORY_ERROR, STACK_OVERFLOW_ERROR, UNKNOWN_ERROR, AWT_ERROR, UNDECLARED_THROWABLE_EXCEPTION, UNSUPPORTED_LOOK_AND_FEEL_EXCEPTION, })); ALL_TEST_THROWABLES = Collections.unmodifiableSet(temp); temp = new ExceptionHashSet(); temp.add(AnySubType.v(Scene.v().getRefType("java.lang.Throwable"))); ALL_THROWABLES_REP = Collections.unmodifiableSet(temp); } /** * Verifies that the argument <code>set</code> is catchable as * any of the exceptions in <code>members</code>. * * @param set <code>ThrowableSet</code> whose membership is * being checked. * * @param members A {@link List} of {@link RefType} objects representing * Throwable classes. * */ public boolean catchableAsAllOf(ThrowableSet set, List members) { boolean result = true; for (Iterator i = members.iterator(); i.hasNext(); ) { RefType member = (RefType) i.next(); result = result && set.catchableAs(member); } return result; } /** * Verifies that the argument <code>set</code> is not catchable as * any of the exceptions in <code>members</code>. * * @param set <code>ThrowableSet</code> whose membership is * being checked. * * @param members A {@link List} of {@link RefType} objects representing * Throwable classes. * */ public boolean catchableAsNoneOf(ThrowableSet set, List members) { boolean result = true; for (Iterator i = members.iterator(); i.hasNext(); ) { RefType member = (RefType) i.next(); result = result && (! set.catchableAs(member)); } return result; } /** * Verifies that the argument <code>set</code> is catchable as * any of the exceptions in <code>members</code>, but not * as any other of the exceptions ALL_TEST_THROWABLES. * * @param set <code>ThrowableSet</code> whose membership is * being checked. * * @param members A {@link List} of {@link RefType} objects representing * Throwable classes. * */ public boolean catchableOnlyAs(ThrowableSet set, List members) { boolean result = true; for (Iterator i = members.iterator(); i.hasNext(); ) { RefType member = (RefType) i.next(); result = result && (set.catchableAs(member)); } for (Iterator i = ALL_TEST_THROWABLES.iterator(); i.hasNext(); ) { RefType e = (RefType) i.next(); if (! members.contains(e)) { result = result && (! set.catchableAs(e)); } } return result; } /** * Returns a Set representation of the subset of ALL_TEST_THROWABLES * which are catchable by the argument <code>ThrowableSet</code> * (for use in assertions about the catchable exceptions. * * @param thrownSet <code>ThrowableSet</code> representing some * set of possible exceptions. */ public Set catchableSubset(ThrowableSet thrownSet) { Set result = new ExceptionHashSet(ALL_TEST_THROWABLES.size()); for (Iterator i = ALL_TEST_THROWABLES.iterator(); i.hasNext(); ) { RefType e = (RefType) i.next(); if (thrownSet.catchableAs(e)) { result.add(e); } } return result; } /** * Checks that the internal representation of the exceptions * in an argument {@link ThrowableSet} matches expectations. * * @param thrownSet {@link ThrowableSet} whose contents are being * checked. * * @param expectedIncludes contains the collection of {@link * RefType} and {@link AnySubType} objects that are expected to be * included in <code>thrownSet</code>. * * @param expectedExcludes contains the collection of {@link * RefType} and {@link AnySubType} objects that are expected to be * excluded from <code>thrownSet</code>. * * @return <code>true</code> if <code>thrownSet</code> and * <code>expected</code> have the same members. */ public static boolean sameMembers(Set expectedIncluded, Set expectedExcluded, ThrowableSet thrownSet) { if ( (expectedIncluded.size() != thrownSet.typesIncluded().size()) || (expectedExcluded.size() != thrownSet.typesExcluded().size()) || (! expectedIncluded.containsAll(thrownSet.typesIncluded())) || (! expectedExcluded.containsAll(thrownSet.typesExcluded()))) { System.out.println("\nExpected included:" + expectedIncluded.toString() + "\nExpected excluded:" + expectedExcluded.toString() + "\nActual:\n" + thrownSet.toString()); return false; } else { return true; } } public static class ExceptionHashSet extends HashSet { // The only difference between this and a standard HashSet is that // we override the toString() method to make ExceptionHashSets // easier to compare when they appear in JUnit assertion failure // messages. ExceptionHashSet() { super(); } ExceptionHashSet(Collection c) { super(c); } ExceptionHashSet(int initialCapacity) { super(initialCapacity); } public String toString() { StringBuffer result = new StringBuffer(); Object[] contents = (Object[]) this.toArray(); Comparator comparator = new Comparator() { public int compare(Object o1, Object o2) { // The order doesn't matter, so long as it is consistent. return o1.toString().compareTo(o2.toString()); } }; Arrays.sort(contents, comparator); result.append("\nExceptionHashSet<"); for (int i = 0; i < contents.length; i++) { result.append("\n\t"); result.append(contents[i].toString()); result.append("<"); result.append(Integer.toHexString(contents[i].hashCode())); result.append(">"); } result.append("\n>ExceptionHashSet"); return result.toString(); } } }