Added classes for exception pruning and adapter for null pointer and
array out of bounds analysis.
This commit is contained in:
parent
9024f19bf6
commit
58dd111203
|
@ -0,0 +1,30 @@
|
|||
package com.ibm.wala.ipa.cfg.exceptionpruning;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
* To filter exceptions you can implement this interface and use it in
|
||||
* combination with {@link ExceptionFilter2EdgeFilter}. For more Details see
|
||||
* package-info.
|
||||
*
|
||||
* @author Stephan Gocht <stephan@gobro.de>
|
||||
*
|
||||
* @param <Instruction>
|
||||
*/
|
||||
public interface ExceptionFilter<Instruction> {
|
||||
/**
|
||||
*
|
||||
* @param instruction
|
||||
* @return if the instruction does always throw an exception
|
||||
*/
|
||||
public boolean alwaysThrowsException(Instruction instruction);
|
||||
|
||||
/**
|
||||
*
|
||||
* @param instruction
|
||||
* @return a list of exceptions, which have to be filtered for the given
|
||||
* instruction
|
||||
*/
|
||||
public Collection<FilteredException> filteredExceptions(
|
||||
Instruction instruction);
|
||||
}
|
|
@ -0,0 +1,83 @@
|
|||
package com.ibm.wala.ipa.cfg.exceptionpruning;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import com.ibm.wala.cfg.ControlFlowGraph;
|
||||
import com.ibm.wala.ipa.cfg.EdgeFilter;
|
||||
import com.ibm.wala.ipa.cha.ClassHierarchy;
|
||||
import com.ibm.wala.ssa.ISSABasicBlock;
|
||||
import com.ibm.wala.ssa.SSAAbstractInvokeInstruction;
|
||||
import com.ibm.wala.ssa.SSAAbstractThrowInstruction;
|
||||
import com.ibm.wala.ssa.SSAInstruction;
|
||||
import com.ibm.wala.types.TypeReference;
|
||||
|
||||
/**
|
||||
* This class converts an exception filter to an edge filter.
|
||||
*
|
||||
* @author Stephan Gocht <stephan@gobro.de>
|
||||
*
|
||||
* @param <Block>
|
||||
*/
|
||||
public class ExceptionFilter2EdgeFilter<Block extends ISSABasicBlock>
|
||||
implements EdgeFilter<Block> {
|
||||
|
||||
private final ExceptionFilter<SSAInstruction> filter;
|
||||
private final ClassHierarchy cha;
|
||||
private final ControlFlowGraph<SSAInstruction, Block> cfg;
|
||||
|
||||
public ExceptionFilter2EdgeFilter(ExceptionFilter<SSAInstruction> filter,
|
||||
ClassHierarchy cha, ControlFlowGraph<SSAInstruction, Block> cfg) {
|
||||
this.cfg = cfg;
|
||||
this.filter = filter;
|
||||
this.cha = cha;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasExceptionalEdge(Block src, Block dst) {
|
||||
boolean hasExceptionalEdge = this.cfg.getExceptionalSuccessors(src)
|
||||
.contains(dst);
|
||||
final SSAInstruction relevantInstruction = src.getLastInstruction();
|
||||
if (hasExceptionalEdge && relevantInstruction != null) {
|
||||
if (this.weKnowAllExceptions(relevantInstruction)) {
|
||||
|
||||
final Collection<TypeReference> thrownExceptions = relevantInstruction
|
||||
.getExceptionTypes();
|
||||
final Collection<FilteredException> filteredExceptions = this.filter
|
||||
.filteredExceptions(relevantInstruction);
|
||||
|
||||
final boolean isFiltered = ExceptionMatcher.isFiltered(
|
||||
thrownExceptions, filteredExceptions, this.cha);
|
||||
hasExceptionalEdge = !isFiltered;
|
||||
}
|
||||
}
|
||||
|
||||
return hasExceptionalEdge;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasNormalEdge(Block src, Block dst) {
|
||||
boolean result = true;
|
||||
|
||||
final SSAInstruction relevantInstruction = src.getLastInstruction();
|
||||
if (relevantInstruction != null
|
||||
&& this.filter.alwaysThrowsException(relevantInstruction)) {
|
||||
result = false;
|
||||
}
|
||||
|
||||
return result && this.cfg.getNormalSuccessors(src).contains(dst);
|
||||
}
|
||||
|
||||
/**
|
||||
* SSAInstruction::getExceptionTypes() does not return exceptions thrown by
|
||||
* throw or invoke instructions, so we may not remove edges from those
|
||||
* instructions, even if all exceptions returned by
|
||||
* instruction.getExceptionTypes() are to be filtered.
|
||||
*
|
||||
* @param instruction
|
||||
* @return if we know all exceptions, that can occur at this address from
|
||||
* getExceptionTypes()
|
||||
*/
|
||||
private boolean weKnowAllExceptions(SSAInstruction instruction) {
|
||||
return !((instruction instanceof SSAAbstractInvokeInstruction) || (instruction instanceof SSAAbstractThrowInstruction));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,111 @@
|
|||
package com.ibm.wala.ipa.cfg.exceptionpruning;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import com.ibm.wala.classLoader.IClass;
|
||||
import com.ibm.wala.ipa.cha.ClassHierarchy;
|
||||
import com.ibm.wala.types.TypeReference;
|
||||
|
||||
/**
|
||||
* Helper class to check if an exception is part of a set of filtered
|
||||
* exceptions.
|
||||
*
|
||||
* @author Stephan Gocht <stephan@gobro.de>
|
||||
*
|
||||
*/
|
||||
public class ExceptionMatcher {
|
||||
/**
|
||||
* @param thrownExceptions
|
||||
* @param filteredExceptions
|
||||
* @param cha
|
||||
* @return true, iff thrownExceptions is part of filteredExceptions
|
||||
*/
|
||||
public static boolean isFiltered(
|
||||
Collection<TypeReference> thrownExceptions,
|
||||
Collection<FilteredException> filteredExceptions, ClassHierarchy cha) {
|
||||
final ExceptionMatcher matcher = new ExceptionMatcher(thrownExceptions,
|
||||
filteredExceptions, cha);
|
||||
return matcher.areAllExceptionsIgnored();
|
||||
}
|
||||
|
||||
private Set<TypeReference> ignoreExact;
|
||||
private Set<TypeReference> ignoreSubclass;
|
||||
private ClassHierarchy cha;
|
||||
|
||||
private final boolean areAllExceptionsIgnored;
|
||||
|
||||
private ExceptionMatcher(Collection<TypeReference> thrownExceptions,
|
||||
Collection<FilteredException> filteredExceptions, ClassHierarchy cha) {
|
||||
this.ignoreExact = new HashSet<>();
|
||||
this.ignoreSubclass = new HashSet<>();
|
||||
this.cha = cha;
|
||||
|
||||
this.fillIgnore(filteredExceptions);
|
||||
|
||||
this.areAllExceptionsIgnored = this
|
||||
.allExceptionsIgnored(thrownExceptions);
|
||||
|
||||
this.free();
|
||||
}
|
||||
|
||||
private boolean allExceptionsIgnored(
|
||||
Collection<TypeReference> thrownExceptions) {
|
||||
boolean allExceptionsIgnored = true;
|
||||
for (final TypeReference exception : thrownExceptions) {
|
||||
allExceptionsIgnored &= this.isFiltered(exception);
|
||||
if (!allExceptionsIgnored) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return allExceptionsIgnored;
|
||||
}
|
||||
|
||||
private boolean areAllExceptionsIgnored() {
|
||||
return this.areAllExceptionsIgnored;
|
||||
}
|
||||
|
||||
private void fillIgnore(Collection<FilteredException> filteredExceptions) {
|
||||
for (final FilteredException filteredException : filteredExceptions) {
|
||||
final TypeReference exception = filteredException.getException();
|
||||
|
||||
this.ignoreExact.add(exception);
|
||||
if (filteredException.isSubclassFiltered()) {
|
||||
this.ignoreSubclass.add(exception);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void free() {
|
||||
this.ignoreExact = null;
|
||||
this.ignoreSubclass = null;
|
||||
this.cha = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the exception itself is filtered or if it is derived from a
|
||||
* filtered exception.
|
||||
*
|
||||
* @param exception
|
||||
* @return if the exception is filtered
|
||||
*/
|
||||
private boolean isFiltered(TypeReference exception) {
|
||||
boolean isFiltered = false;
|
||||
if (this.ignoreExact.contains(exception)) {
|
||||
isFiltered = true;
|
||||
} else {
|
||||
for (final TypeReference ignoreException : this.ignoreSubclass) {
|
||||
final IClass exceptionClass = this.cha.lookupClass(exception);
|
||||
final IClass ignoreClass = this.cha
|
||||
.lookupClass(ignoreException);
|
||||
if (this.cha.isAssignableFrom(ignoreClass, exceptionClass)) {
|
||||
isFiltered = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return isFiltered;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
package com.ibm.wala.ipa.cfg.exceptionpruning;
|
||||
|
||||
import com.ibm.wala.types.TypeReference;
|
||||
|
||||
/**
|
||||
* FilteredException represents either a single exception or an exception and
|
||||
* all its subclasses.
|
||||
*
|
||||
* @author Stephan Gocht <stephan@gobro.de>
|
||||
*
|
||||
*/
|
||||
public class FilteredException {
|
||||
public static final boolean FILTER_SUBCLASSES = true;
|
||||
private final TypeReference exception;
|
||||
|
||||
private final boolean isSubclassFiltered;
|
||||
|
||||
public FilteredException(TypeReference exception) {
|
||||
this(exception, false);
|
||||
}
|
||||
|
||||
public FilteredException(TypeReference exception, boolean isSubclassFiltered) {
|
||||
super();
|
||||
this.exception = exception;
|
||||
this.isSubclassFiltered = isSubclassFiltered;
|
||||
}
|
||||
|
||||
public TypeReference getException() {
|
||||
return this.exception;
|
||||
}
|
||||
|
||||
public boolean isSubclassFiltered() {
|
||||
return this.isSubclassFiltered;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
package com.ibm.wala.ipa.cfg.exceptionpruning.filter;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedList;
|
||||
|
||||
import com.ibm.wala.analysis.arraybounds.ArrayOutOfBoundsAnalysis;
|
||||
import com.ibm.wala.analysis.arraybounds.ArrayOutOfBoundsAnalysis.UnnecessaryCheck;
|
||||
import com.ibm.wala.ipa.cfg.exceptionpruning.ExceptionFilter;
|
||||
import com.ibm.wala.ipa.cfg.exceptionpruning.FilteredException;
|
||||
import com.ibm.wala.ssa.SSAInstruction;
|
||||
import com.ibm.wala.types.TypeReference;
|
||||
|
||||
/**
|
||||
* Adapter for using {@link ArrayOutOfBoundsAnalysis}. This filter is filtering
|
||||
* ArrayOutOfBoundException, which can not occur.
|
||||
*
|
||||
* @author Stephan Gocht <stephan@gobro.de>
|
||||
*
|
||||
*/
|
||||
public class ArrayOutOfBoundFilter implements ExceptionFilter<SSAInstruction> {
|
||||
private final ArrayOutOfBoundsAnalysis analysis;
|
||||
|
||||
public ArrayOutOfBoundFilter(ArrayOutOfBoundsAnalysis analysis) {
|
||||
this.analysis = analysis;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean alwaysThrowsException(SSAInstruction instruction) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<FilteredException> filteredExceptions(
|
||||
SSAInstruction instruction) {
|
||||
final UnnecessaryCheck unnecessary = this.analysis
|
||||
.getBoundsCheckNecessary().get(instruction);
|
||||
if (unnecessary == UnnecessaryCheck.BOTH) {
|
||||
|
||||
final LinkedList<FilteredException> result = new LinkedList<FilteredException>();
|
||||
result.add(new FilteredException(
|
||||
TypeReference.JavaLangArrayIndexOutOfBoundsException));
|
||||
|
||||
return result;
|
||||
} else {
|
||||
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
package com.ibm.wala.ipa.cfg.exceptionpruning.filter;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.LinkedList;
|
||||
|
||||
import com.ibm.wala.ipa.cfg.exceptionpruning.ExceptionFilter;
|
||||
import com.ibm.wala.ipa.cfg.exceptionpruning.FilteredException;
|
||||
import com.ibm.wala.ssa.SSAInstruction;
|
||||
|
||||
/**
|
||||
* Use this class to combine multiple {@link ExceptionFilter}
|
||||
*
|
||||
* @author Stephan Gocht <stephan@gobro.de>
|
||||
*/
|
||||
public class CombinedExceptionFilter implements ExceptionFilter<SSAInstruction> {
|
||||
private final Collection<ExceptionFilter<SSAInstruction>> exceptionFilter;
|
||||
|
||||
public CombinedExceptionFilter() {
|
||||
this.exceptionFilter = new LinkedList<>();
|
||||
}
|
||||
|
||||
public CombinedExceptionFilter(
|
||||
Collection<ExceptionFilter<SSAInstruction>> exceptionFilter) {
|
||||
this.exceptionFilter = exceptionFilter;
|
||||
}
|
||||
|
||||
public boolean add(ExceptionFilter<SSAInstruction> e) {
|
||||
return this.exceptionFilter.add(e);
|
||||
}
|
||||
|
||||
public boolean addAll(
|
||||
Collection<? extends ExceptionFilter<SSAInstruction>> c) {
|
||||
return this.exceptionFilter.addAll(c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean alwaysThrowsException(SSAInstruction instruction) {
|
||||
boolean result = false;
|
||||
|
||||
for (final ExceptionFilter<SSAInstruction> filter : this.exceptionFilter) {
|
||||
result |= filter.alwaysThrowsException(instruction);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<FilteredException> filteredExceptions(
|
||||
SSAInstruction instruction) {
|
||||
final LinkedList<FilteredException> result = new LinkedList<>();
|
||||
for (final ExceptionFilter<SSAInstruction> filter : this.exceptionFilter) {
|
||||
result.addAll(filter.filteredExceptions(instruction));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,60 @@
|
|||
package com.ibm.wala.ipa.cfg.exceptionpruning.filter;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.LinkedList;
|
||||
|
||||
import com.ibm.wala.ipa.cfg.exceptionpruning.ExceptionFilter;
|
||||
import com.ibm.wala.ipa.cfg.exceptionpruning.FilteredException;
|
||||
import com.ibm.wala.ssa.SSAInstruction;
|
||||
import com.ibm.wala.types.TypeReference;
|
||||
|
||||
/**
|
||||
* For filtering specific exceptions.
|
||||
*
|
||||
* @author Stephan Gocht <stephan@gobro.de>
|
||||
*
|
||||
*/
|
||||
public class IgnoreExceptionsFilter implements ExceptionFilter<SSAInstruction> {
|
||||
private final Collection<FilteredException> toBeIgnored;
|
||||
|
||||
/**
|
||||
* All given exceptions and subclasses will be ignored.
|
||||
*
|
||||
* @param toBeIgnored
|
||||
*/
|
||||
public IgnoreExceptionsFilter(Collection<TypeReference> toBeIgnored) {
|
||||
this.toBeIgnored = new LinkedList<>();
|
||||
|
||||
this.addAll(toBeIgnored);
|
||||
}
|
||||
|
||||
/**
|
||||
* The given exception and subclasses will be ignored.
|
||||
*/
|
||||
public IgnoreExceptionsFilter(TypeReference toBeIgnored) {
|
||||
this.toBeIgnored = new LinkedList<>();
|
||||
|
||||
final LinkedList<TypeReference> list = new LinkedList<>();
|
||||
list.add(toBeIgnored);
|
||||
|
||||
this.addAll(list);
|
||||
}
|
||||
|
||||
private void addAll(Collection<TypeReference> toBeIgnored) {
|
||||
for (final TypeReference ignored : toBeIgnored) {
|
||||
this.toBeIgnored.add(new FilteredException(ignored,
|
||||
FilteredException.FILTER_SUBCLASSES));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean alwaysThrowsException(SSAInstruction instruction) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<FilteredException> filteredExceptions(
|
||||
SSAInstruction instruction) {
|
||||
return this.toBeIgnored;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
package com.ibm.wala.ipa.cfg.exceptionpruning.filter;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedList;
|
||||
|
||||
import com.ibm.wala.analysis.nullpointer.IntraproceduralNullPointerAnalysis;
|
||||
import com.ibm.wala.cfg.exc.intra.NullPointerState.State;
|
||||
import com.ibm.wala.ipa.cfg.exceptionpruning.ExceptionFilter;
|
||||
import com.ibm.wala.ipa.cfg.exceptionpruning.FilteredException;
|
||||
import com.ibm.wala.ssa.ISSABasicBlock;
|
||||
import com.ibm.wala.ssa.SSAInstruction;
|
||||
import com.ibm.wala.types.TypeReference;
|
||||
|
||||
/**
|
||||
* Adapter for {@link IntraproceduralNullPointerAnalysis}. This filter is filtering
|
||||
* NullPointerException, which can not occur.
|
||||
*
|
||||
* @author Stephan Gocht <stephan@gobro.de>
|
||||
*
|
||||
* @param <T>
|
||||
*/
|
||||
public class NullPointerExceptionFilter<T extends ISSABasicBlock> implements
|
||||
ExceptionFilter<SSAInstruction> {
|
||||
private final IntraproceduralNullPointerAnalysis<T> analysis;
|
||||
|
||||
public NullPointerExceptionFilter(IntraproceduralNullPointerAnalysis<T> analysis) {
|
||||
this.analysis = analysis;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean alwaysThrowsException(SSAInstruction instruction) {
|
||||
return this.analysis.nullPointerExceptionThrowState(instruction) == State.NULL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<FilteredException> filteredExceptions(
|
||||
SSAInstruction instruction) {
|
||||
if (this.analysis.nullPointerExceptionThrowState(instruction) == State.NOT_NULL) {
|
||||
final LinkedList<FilteredException> result = new LinkedList<FilteredException>();
|
||||
result.add(new FilteredException(
|
||||
TypeReference.JavaLangNullPointerException));
|
||||
return result;
|
||||
} else {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
/**
|
||||
* All available filters should be contained in this package.
|
||||
*
|
||||
* @author Stephan Gocht <stephan@gobro.de>
|
||||
*
|
||||
*/
|
||||
package com.ibm.wala.ipa.cfg.exceptionpruning.filter;
|
|
@ -0,0 +1,15 @@
|
|||
/**
|
||||
* If we want to filter edges of a control flow graph we already have
|
||||
* {@link com.ibm.wala.ipa.cfg.EdgeFilter}, but if we want to remove
|
||||
* exceptions in particular we may want to combine different analysis.
|
||||
* Therefore we need a possibility to collect a set of removed exceptions,
|
||||
* so that an exceptional edge may be removed as soon as all exceptions,
|
||||
* which can occur along these edge are filtered.
|
||||
*
|
||||
* This package contains classes for this job and also adapter for some
|
||||
* analysis.
|
||||
*
|
||||
* @author Stephan Gocht <stephan@gobro.de>
|
||||
*
|
||||
*/
|
||||
package com.ibm.wala.ipa.cfg.exceptionpruning;
|
Loading…
Reference in New Issue