Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions docs/en/pointer-analysis-framework.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,10 @@ See <<taint-analysis#taint-analysis,Taint Analysis>> for more details.
** Default value: `false`
** Specify whether to dump points-to results in YAML format. This option is independent of `dump` and `dump-ci` output formats.

* Only dump points-to results of application code: `only-dump-app:[true|false]`
** Default value: `false`
** When set to `true`, `dump-yaml`, `dump-ci` will only dump analysis results of application code (and ignores library code).

* Time limit: `time-limit:<time-limit>`
** Default value: `-1`
** Specify a time limit for pointer analysis (unit: second).When it is `-1`, there is no time limit.
Expand Down
6 changes: 2 additions & 4 deletions src/main/java/pascal/taie/AbstractWorldBuilder.java
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,6 @@ public abstract class AbstractWorldBuilder implements WorldBuilder {

private static final Logger logger = LogManager.getLogger(AbstractWorldBuilder.class);

protected static final String JREs = "java-benchmarks/JREs";

protected static final List<String> implicitEntries = List.of(
"<java.lang.System: void initializeSystemClass()>",
"<java.lang.Thread: void <init>(java.lang.ThreadGroup,java.lang.Runnable)>",
Expand All @@ -75,7 +73,7 @@ protected static String getClassPath(Options options) {
.collect(Collectors.joining(File.pathSeparator));
} else { // when prependJVM is not set, we manually specify JRE jars
// check existence of JREs
File jreDir = new File(JREs);
File jreDir = new File(options.getLibJREPath());
if (!jreDir.exists()) {
throw new RuntimeException("""
Failed to locate Java library.
Expand All @@ -85,7 +83,7 @@ protected static String getClassPath(Options options) {
then put it in Tai-e's working directory.""");
}
String jrePath = String.format("%s/jre1.%d",
JREs, options.getJavaVersion());
options.getLibJREPath(), options.getJavaVersion());
try (Stream<Path> paths = Files.walk(Path.of(jrePath))) {
return Streams.concat(
paths.map(Path::toString).filter(p -> p.endsWith(".jar")),
Expand Down
12 changes: 12 additions & 0 deletions src/main/java/pascal/taie/analysis/graph/flowgraph/FlowKind.java
Original file line number Diff line number Diff line change
Expand Up @@ -39,5 +39,17 @@ public enum FlowKind {
PARAMETER_PASSING,
RETURN,

// cut-shortcut
ARG_TO_HOST, // container entrance method, for example, v.add(e), o \in pts(v), e -> host(o)
HOST_TO_RESULT,
SUBSET,
CORRELATION,
ARRAYCOPY,
ID,
VIRTUAL_ARRAY,
VIRTUAL_ARG,
SET, GET,
NON_RELAY_GET, // relay edge

OTHER,
}
53 changes: 37 additions & 16 deletions src/main/java/pascal/taie/analysis/pta/PointerAnalysis.java
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
import pascal.taie.analysis.pta.core.cs.selector.ContextSelectorFactory;
import pascal.taie.analysis.pta.core.heap.AllocationSiteBasedModel;
import pascal.taie.analysis.pta.core.heap.HeapModel;
import pascal.taie.analysis.pta.core.solver.CutShortcutSolver;
import pascal.taie.analysis.pta.core.solver.DefaultSolver;
import pascal.taie.analysis.pta.core.solver.Solver;
import pascal.taie.analysis.pta.plugin.AnalysisTimer;
Expand All @@ -40,6 +41,10 @@
import pascal.taie.analysis.pta.plugin.ReferenceHandler;
import pascal.taie.analysis.pta.plugin.ResultProcessor;
import pascal.taie.analysis.pta.plugin.ThreadHandler;
import pascal.taie.analysis.pta.plugin.cutshortcut.container.ContainerAccessHandler;
import pascal.taie.analysis.pta.plugin.cutshortcut.container.MakeDefaultContainerConfig;
import pascal.taie.analysis.pta.plugin.cutshortcut.field.FieldAccessHandler;
import pascal.taie.analysis.pta.plugin.cutshortcut.localflow.LocalFlowHandler;
import pascal.taie.analysis.pta.plugin.exception.ExceptionAnalysis;
import pascal.taie.analysis.pta.plugin.invokedynamic.InvokeDynamicAnalysis;
import pascal.taie.analysis.pta.plugin.invokedynamic.Java9StringConcatHandler;
Expand Down Expand Up @@ -75,52 +80,59 @@ public PointerAnalysisResult analyze() {
HeapModel heapModel = new AllocationSiteBasedModel(options);
ContextSelector selector = null;
String advanced = options.getString("advanced");
String solverType = options.has("solver") ? options.getString("solver"): "default"; // which solver to use
String cs = options.getString("cs");
if (advanced != null) {
if (advanced.equals("collection")) {
if (advanced.equals("collection"))
selector = ContextSelectorFactory.makeSelectiveSelector(cs,
new CollectionMethods(World.get().getClassHierarchy()).get());
} else {
else {
// run context-insensitive analysis as pre-analysis
PointerAnalysisResult preResult = runAnalysis(heapModel,
ContextSelectorFactory.makeCISelector());
if (advanced.startsWith("scaler")) {
PointerAnalysisResult preResult = runAnalysis(heapModel, ContextSelectorFactory.makeCISelector(), solverType);
if (advanced.startsWith("scaler"))
selector = Monitor.runAndCount(() -> ContextSelectorFactory
.makeGuidedSelector(Scaler.run(preResult, advanced)),
"Scaler", Level.INFO);
} else if (advanced.startsWith("zipper")) {
else if (advanced.startsWith("zipper"))
selector = Monitor.runAndCount(() -> ContextSelectorFactory
.makeSelectiveSelector(cs, Zipper.run(preResult, advanced)),
"Zipper", Level.INFO);
} else if (advanced.equals("mahjong")) {
else if (advanced.equals("mahjong"))
heapModel = Monitor.runAndCount(() -> Mahjong.run(preResult, options),
"Mahjong", Level.INFO);
} else {
else
throw new IllegalArgumentException(
"Illegal advanced analysis argument: " + advanced);
}

}
}
if (selector == null) {
selector = ContextSelectorFactory.makePlainSelector(cs);
}
return runAnalysis(heapModel, selector);
return runAnalysis(heapModel, selector, solverType);
}

private PointerAnalysisResult runAnalysis(HeapModel heapModel,
ContextSelector selector) {
ContextSelector selector,
String solverType) {
AnalysisOptions options = getOptions();
Solver solver = new DefaultSolver(options,
heapModel, selector, new MapBasedCSManager());
Solver solver;
if (solverType.equals("default"))
solver = new DefaultSolver(options, heapModel, selector, new MapBasedCSManager());
// cut-shortcut
else if (solverType.equals("csc"))
solver = new CutShortcutSolver(options, heapModel, selector, new MapBasedCSManager());
else
throw new IllegalArgumentException("Illegal solver type: " + solverType);
// The initialization of some Plugins may read the fields in solver,
// e.g., contextSelector or csManager, thus we initialize Plugins
// after setting all other fields of solver.
setPlugin(solver, options);
// after setting all other fields of solver.setPlugin(solver, options);
setPlugin(solver, options, solverType);
solver.solve();
return solver.getResult();
}

private static void setPlugin(Solver solver, AnalysisOptions options) {
private static void setPlugin(Solver solver, AnalysisOptions options, String solverType) {
CompositePlugin plugin = new CompositePlugin();
// add builtin plugins
// To record elapsed time precisely, AnalysisTimer should be added at first.
Expand All @@ -132,6 +144,15 @@ private static void setPlugin(Solver solver, AnalysisOptions options) {
new NativeModeller(),
new ExceptionAnalysis()
);
if (solverType.equals("csc")) {
MakeDefaultContainerConfig.make();
plugin.addPlugin(
new LocalFlowHandler(),
new FieldAccessHandler(),
new ContainerAccessHandler()
);
}

int javaVersion = World.get().getOptions().getJavaVersion();
if (javaVersion < 9) {
// current reference handler doesn't support Java 9+
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@ abstract class AbstractPointer implements Pointer {

private final ArrayList<PointerFlowEdge> outEdges = new ArrayList<>(4);

private final ArrayList<PointerFlowEdge> inEdges = new ArrayList<>(4);

private Set<Predicate<CSObj>> filters = Set.of();

protected AbstractPointer(int index) {
Expand Down Expand Up @@ -95,6 +97,7 @@ public PointerFlowEdge addEdge(PointerFlowEdge edge) {
assert edge.source() == this;
if (successors.add(edge.target())) {
outEdges.add(edge);
edge.target().addInEdge(edge);
return edge;
} else if (edge.kind() == FlowKind.OTHER) {
for (PointerFlowEdge outEdge : outEdges) {
Expand All @@ -103,11 +106,17 @@ public PointerFlowEdge addEdge(PointerFlowEdge edge) {
}
}
outEdges.add(edge);
edge.target().addInEdge(edge);
return edge;
}
return null;
}

public void addInEdge(PointerFlowEdge edge) {
assert edge.target() == this;
inEdges.add(edge);
}

@Override
public void removeEdgesIf(Predicate<PointerFlowEdge> filter) {
outEdges.removeIf(filter);
Expand All @@ -118,6 +127,11 @@ public Set<PointerFlowEdge> getOutEdges() {
return Collections.unmodifiableSet(new ArraySet<>(outEdges, true));
}

@Override
public Set<PointerFlowEdge> getInEdges() {
return Collections.unmodifiableSet(new ArraySet<>(inEdges, true));
}

@Override
public int getOutDegree() {
return outEdges.size();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@

import pascal.taie.analysis.pta.core.cs.context.Context;
import pascal.taie.analysis.pta.core.heap.Obj;

import pascal.taie.ir.exp.Var;
import pascal.taie.ir.stmt.Invoke;
import pascal.taie.language.classes.JField;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,8 @@ public interface Pointer extends Indexable {
*/
PointerFlowEdge addEdge(PointerFlowEdge edge);

void addInEdge(PointerFlowEdge edge);

/**
* Removes out edges of this pointer if they satisfy the filter.
* <p>
Expand All @@ -112,6 +114,11 @@ public interface Pointer extends Indexable {
*/
Set<PointerFlowEdge> getOutEdges();

/**
* @return out edges of this pointer in pointer flow graph.
*/
Set<PointerFlowEdge> getInEdges();

/**
* @return out degree of this pointer in pointer flow graph.
*/
Expand Down
Loading