Added classes for exception pruning and adapter for null pointer and

array out of bounds analysis.
This commit is contained in:
Stephan Gocht 2015-10-12 19:52:29 +02:00
parent 9024f19bf6
commit 58dd111203
10 changed files with 495 additions and 0 deletions

View File

@ -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);
}

View File

@ -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));
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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();
}
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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();
}
}
}

View File

@ -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;

View File

@ -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;