Enhanced pointer analysis to reason that arrays known to be of zero length

cannot have any contents.
This commit is contained in:
Manu Sridharan 2012-05-09 15:35:54 -06:00
parent 28a351200d
commit c415f3e0fd
7 changed files with 162 additions and 3 deletions

View File

@ -0,0 +1,20 @@
/*******************************************************************************
* Copyright (c) 2008 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 arrayAlias;
public class TestZeroLengthArray {
public static void main(String[] args) {
Object[] arr = new Object[0];
// this will throw an exception; use it to test pointer analysis precision
arr[0] = new Object();
}
}

View File

@ -0,0 +1,71 @@
/*******************************************************************************
* Copyright (c) 2008 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.core.tests.ptrs;
import java.io.IOException;
import junit.framework.Assert;
import org.junit.Test;
import com.ibm.wala.core.tests.callGraph.CallGraphTestUtil;
import com.ibm.wala.core.tests.util.TestConstants;
import com.ibm.wala.ipa.callgraph.AnalysisCache;
import com.ibm.wala.ipa.callgraph.AnalysisOptions;
import com.ibm.wala.ipa.callgraph.AnalysisScope;
import com.ibm.wala.ipa.callgraph.CGNode;
import com.ibm.wala.ipa.callgraph.CallGraph;
import com.ibm.wala.ipa.callgraph.CallGraphBuilder;
import com.ibm.wala.ipa.callgraph.Entrypoint;
import com.ibm.wala.ipa.callgraph.impl.Everywhere;
import com.ibm.wala.ipa.callgraph.impl.Util;
import com.ibm.wala.ipa.callgraph.propagation.HeapModel;
import com.ibm.wala.ipa.callgraph.propagation.InstanceKey;
import com.ibm.wala.ipa.callgraph.propagation.PointerAnalysis;
import com.ibm.wala.ipa.cha.ClassHierarchy;
import com.ibm.wala.ipa.cha.ClassHierarchyException;
import com.ibm.wala.types.ClassLoaderReference;
import com.ibm.wala.types.MethodReference;
import com.ibm.wala.types.Selector;
import com.ibm.wala.types.TypeReference;
import com.ibm.wala.util.CancelException;
import com.ibm.wala.util.intset.OrdinalSet;
public class ZeroLengthArrayTest {
@Test
public void testZeroLengthArray() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException {
AnalysisScope scope = CallGraphTestUtil.makeJ2SEAnalysisScope(TestConstants.WALA_TESTDATA,
CallGraphTestUtil.REGRESSION_EXCLUSIONS);
ClassHierarchy cha = ClassHierarchy.make(scope);
Iterable<Entrypoint> entrypoints = com.ibm.wala.ipa.callgraph.impl.Util.makeMainEntrypoints(scope, cha,
TestConstants.ZERO_LENGTH_ARRAY_MAIN);
AnalysisOptions options = CallGraphTestUtil.makeAnalysisOptions(scope, entrypoints);
CallGraphBuilder builder = Util.makeVanillaZeroOneCFABuilder(options, new AnalysisCache(), cha, scope);
CallGraph cg = builder.makeCallGraph(options, null);
PointerAnalysis pa = builder.getPointerAnalysis();
// System.err.println(pa);
HeapModel heapModel = pa.getHeapModel();
CGNode mainNode = cg.getNode(
cha.resolveMethod(MethodReference.findOrCreate(
TypeReference.findOrCreate(ClassLoaderReference.Application, TestConstants.ZERO_LENGTH_ARRAY_MAIN),
Selector.make("main([Ljava/lang/String;)V"))), Everywhere.EVERYWHERE);
OrdinalSet<InstanceKey> pointsToSet = pa.getPointsToSet(heapModel.getPointerKeyForLocal(mainNode, 4));
Assert.assertEquals(1, pointsToSet.size());
InstanceKey arrayKey = pointsToSet.iterator().next();
OrdinalSet<InstanceKey> arrayContents = pa.getPointsToSet(heapModel.getPointerKeyForArrayContents(arrayKey));
System.err.println(arrayContents);
Assert.assertEquals(0, arrayContents.size());
}
}

View File

@ -40,6 +40,8 @@ public interface TestConstants {
public final static String ARRAY_ALIAS_MAIN = "LarrayAlias/TestArrayAlias";
public final static String ZERO_LENGTH_ARRAY_MAIN = "LarrayAlias/TestZeroLengthArray";
public final static String REFLECT1_MAIN = "Lreflection/Reflect1";
public final static String REFLECT2_MAIN = "Lreflection/Reflect2";

View File

@ -20,6 +20,8 @@ import com.ibm.wala.ipa.callgraph.CGNode;
import com.ibm.wala.ipa.callgraph.propagation.cfa.CallerContext;
import com.ibm.wala.ipa.callgraph.propagation.cfa.ContainerContextSelector;
import com.ibm.wala.ipa.cha.IClassHierarchy;
import com.ibm.wala.ssa.IR;
import com.ibm.wala.ssa.SSANewInstruction;
import com.ibm.wala.types.TypeReference;
/**
@ -63,16 +65,31 @@ public class AllocationSiteInNodeFactory implements InstanceKeyFactory {
return null;
}
CGNode nodeToUse = node;
// disallow recursion in contexts.
if (node.getContext() instanceof ReceiverInstanceContext || node.getContext() instanceof CallerContext) {
IMethod m = node.getMethod();
CGNode n = ContainerContextSelector.findNodeRecursiveMatchingContext(m, node.getContext());
if (n != null) {
return new NormalAllocationInNode(n, allocation, type);
nodeToUse = n;
}
}
InstanceKey key = new NormalAllocationInNode(node, allocation, type);
if (type.isArrayClass()) {
// special case for arrays with zero length in their first dimension
IR ir = node.getIR();
SSANewInstruction newInstruction = ir.getNew(allocation);
int lengthVN = newInstruction.getUse(0);
if (ir.getSymbolTable().isIntegerConstant(lengthVN)) {
Integer c = (Integer) ir.getSymbolTable().getConstantValue(lengthVN);
if (c.intValue() == 0) {
return new ZeroLengthArrayInNode(nodeToUse, allocation, type);
}
}
}
InstanceKey key = new NormalAllocationInNode(nodeToUse, allocation, type);
return key;
}

View File

@ -912,6 +912,9 @@ public abstract class PropagationCallGraphBuilder implements CallGraphBuilder {
if (!I.getConcreteType().isArrayClass()) {
continue;
}
if (I instanceof ZeroLengthArrayInNode) {
continue;
}
TypeReference C = I.getConcreteType().getReference().getArrayElementType();
if (C.isPrimitiveType()) {
continue;
@ -1292,6 +1295,9 @@ public abstract class PropagationCallGraphBuilder implements CallGraphBuilder {
if (!I.getConcreteType().isArrayClass()) {
return;
}
if (I instanceof ZeroLengthArrayInNode) {
return;
}
TypeReference C = I.getConcreteType().getReference().getArrayElementType();
if (C.isPrimitiveType()) {
return;

View File

@ -703,7 +703,7 @@ public abstract class SSAPropagationCallGraphBuilder extends PropagationCallGrap
InstanceKey[] ik = getInvariantContents(arrayRef);
for (int i = 0; i < ik.length; i++) {
if (!representsNullType(ik[i])) {
if (!representsNullType(ik[i]) && !(ik[i] instanceof ZeroLengthArrayInNode)) {
system.findOrCreateIndexForInstanceKey(ik[i]);
PointerKey p = getPointerKeyForArrayContents(ik[i]);
IClass contents = ((ArrayClass) ik[i].getConcreteType()).getElementClass();

View File

@ -0,0 +1,43 @@
/*******************************************************************************
* Copyright (c) 2007 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.ipa.callgraph.propagation;
import com.ibm.wala.classLoader.IClass;
import com.ibm.wala.classLoader.NewSiteReference;
import com.ibm.wala.ipa.callgraph.CGNode;
/**
* Represents an array with length zero. Useful for precision since such arrays
* cannot have contents.
*/
public final class ZeroLengthArrayInNode extends AllocationSiteInNode {
public ZeroLengthArrayInNode(CGNode node, NewSiteReference allocation, IClass type) {
super(node, allocation, type);
}
@Override
public boolean equals(Object obj) {
// instanceof is OK because this class is final
if (obj instanceof ZeroLengthArrayInNode) {
AllocationSiteInNode other = (AllocationSiteInNode) obj;
return getNode().equals(other.getNode()) && getSite().equals(other.getSite());
} else {
return false;
}
}
@Override
public int hashCode() {
return getNode().hashCode() * 8647 + getSite().hashCode();
}
}