Enhanced pointer analysis to reason that arrays known to be of zero length
cannot have any contents.
This commit is contained in:
parent
28a351200d
commit
c415f3e0fd
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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());
|
||||
|
||||
}
|
||||
}
|
|
@ -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";
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue