Skip to content

Commit

Permalink
Add test cases for customized entry points
Browse files Browse the repository at this point in the history
  • Loading branch information
zhangt2333 committed Sep 5, 2023
1 parent cb49dd9 commit c45e1c4
Show file tree
Hide file tree
Showing 3 changed files with 302 additions and 0 deletions.
101 changes: 101 additions & 0 deletions src/test/java/pascal/taie/analysis/pta/CustomEntryPointPlugin.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
/*
* Tai-e: A Static Analysis Framework for Java
*
* Copyright (C) 2022 Tian Tan <tiantan@nju.edu.cn>
* Copyright (C) 2022 Yue Li <yueli@nju.edu.cn>
*
* This file is part of Tai-e.
*
* Tai-e is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation, either version 3
* of the License, or (at your option) any later version.
*
* Tai-e is distributed in the hope that it will be useful,but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General
* Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with Tai-e. If not, see <https://www.gnu.org/licenses/>.
*/

package pascal.taie.analysis.pta;

import pascal.taie.analysis.pta.core.heap.Descriptor;
import pascal.taie.analysis.pta.core.heap.HeapModel;
import pascal.taie.analysis.pta.core.heap.Obj;
import pascal.taie.analysis.pta.core.solver.DeclaredParamProvider;
import pascal.taie.analysis.pta.core.solver.EmptyParamProvider;
import pascal.taie.analysis.pta.core.solver.EntryPoint;
import pascal.taie.analysis.pta.core.solver.Solver;
import pascal.taie.analysis.pta.core.solver.SpecifiedParamProvider;
import pascal.taie.analysis.pta.plugin.Plugin;
import pascal.taie.language.classes.ClassHierarchy;
import pascal.taie.language.classes.ClassNames;
import pascal.taie.language.classes.JClass;
import pascal.taie.language.classes.JField;
import pascal.taie.language.classes.JMethod;
import pascal.taie.language.type.TypeSystem;

public class CustomEntryPointPlugin implements Plugin {

private Solver solver;

private ClassHierarchy hierarchy;

private TypeSystem typeSystem;

private HeapModel heapModel;

@Override
public void setSolver(Solver solver) {
this.solver = solver;
this.hierarchy = solver.getHierarchy();
this.typeSystem = solver.getTypeSystem();
this.heapModel = solver.getHeapModel();
}

@Override
public void onStart() {
JClass clz = hierarchy.getClass("CustomEntryPoints");
assert clz != null;

JMethod emptyParam = clz.getDeclaredMethod("entryWithEmptyParam");
assert emptyParam != null;
solver.addEntryPoint(new EntryPoint(emptyParam, EmptyParamProvider.get()));

JMethod declaredParam1 = clz.getDeclaredMethod("entryWithDeclaredParam1");
assert declaredParam1 != null;
solver.addEntryPoint(new EntryPoint(
declaredParam1, new DeclaredParamProvider(declaredParam1, heapModel, 1)));

JMethod declaredParam2 = clz.getDeclaredMethod("entryWithDeclaredParam2");
assert declaredParam2 != null;
solver.addEntryPoint(new EntryPoint(
declaredParam2, new DeclaredParamProvider(declaredParam2, heapModel, 2)));

JMethod specifiedParam = clz.getDeclaredMethod("entryWithSpecifiedParam");
assert specifiedParam != null;
SpecifiedParamProvider.Builder paramProviderBuilder =
new SpecifiedParamProvider.Builder(specifiedParam);
Obj thisObj = heapModel.getMockObj(Descriptor.ENTRY_DESC, "MethodParam{this}",
clz.getType(), specifiedParam);
Obj p0 = heapModel.getMockObj(Descriptor.ENTRY_DESC, "MethodParam{0}",
specifiedParam.getParamType(0), specifiedParam);
Obj p1 = heapModel.getMockObj(Descriptor.ENTRY_DESC, "MethodParam{1}",
specifiedParam.getParamType(1), specifiedParam);
Obj stringObj = heapModel.getMockObj(Descriptor.ENTRY_DESC, "MethodParam{0}.s1",
typeSystem.getType(ClassNames.STRING), specifiedParam);
Obj param1Obj = heapModel.getMockObj(Descriptor.ENTRY_DESC, "MethodParam{1}[*]",
typeSystem.getType("Param1"), specifiedParam);
JField s1Field = hierarchy.getField("<Param1: java.lang.String s1>");
paramProviderBuilder.addThisObj(thisObj)
.addParamObj(0, p0)
.addFieldObj(p0, s1Field, stringObj)
.addParamObj(1, p1)
.addArrayObj(p1, param1Obj)
.setDelegate(new DeclaredParamProvider(specifiedParam, heapModel));
solver.addEntryPoint(new EntryPoint(specifiedParam, paramProviderBuilder.build()));
}
}
121 changes: 121 additions & 0 deletions src/test/java/pascal/taie/analysis/pta/CustomEntryPointTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
/*
* Tai-e: A Static Analysis Framework for Java
*
* Copyright (C) 2022 Tian Tan <tiantan@nju.edu.cn>
* Copyright (C) 2022 Yue Li <yueli@nju.edu.cn>
*
* This file is part of Tai-e.
*
* Tai-e is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation, either version 3
* of the License, or (at your option) any later version.
*
* Tai-e is distributed in the hope that it will be useful,but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General
* Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with Tai-e. If not, see <https://www.gnu.org/licenses/>.
*/

package pascal.taie.analysis.pta;

import org.junit.jupiter.api.Test;
import pascal.taie.Main;
import pascal.taie.World;
import pascal.taie.analysis.graph.callgraph.CallGraph;
import pascal.taie.analysis.graph.callgraph.CallGraphBuilder;
import pascal.taie.analysis.graph.callgraph.Edge;
import pascal.taie.ir.stmt.Invoke;
import pascal.taie.language.classes.ClassHierarchy;
import pascal.taie.language.classes.JMethod;
import pascal.taie.util.collection.MultiMap;
import pascal.taie.util.collection.MultiMapCollector;

import static org.junit.jupiter.api.Assertions.assertEquals;


public class CustomEntryPointTest {

private static final String[][] CALLER_CALLEE_RELATIONS = {
{
"false",
"<CustomEntryPoints: void entryWithEmptyParam(Param1,Param1[])>",
"<Param1: java.lang.String getS1()>",
},
{
"false",
"<CustomEntryPoints: void entryWithEmptyParam(Param1,Param1[])>",
"<Param1: void setS2(java.lang.String)>",
},
{
"true",
"<CustomEntryPoints: void entryWithDeclaredParam1(Param1,Param1[])>",
"<Param1: java.lang.String getS1()>",
},
{
"true",
"<CustomEntryPoints: void entryWithDeclaredParam1(Param1,Param1[])>",
"<Param1: void setS2(java.lang.String)>",
},
{
"true",
"<CustomEntryPoints: void entryWithDeclaredParam2(Param2)>",
"<Param2: java.lang.String getS1()>",
},
{
"true",
"<CustomEntryPoints: void entryWithDeclaredParam2(Param2)>",
"<Param2: Param1 getP1()>",
},
{
"true",
"<CustomEntryPoints: void entryWithDeclaredParam2(Param2)>",
"<Param1: java.lang.String getS2()>",
},
{
"true",
"<CustomEntryPoints: void entryWithSpecifiedParam(Param1,Param1[],java.lang.String)>",
"<Param1: java.lang.String getS1()>",
},
{
"true",
"<CustomEntryPoints: void entryWithSpecifiedParam(Param1,Param1[],java.lang.String)>",
"<Param1: void setS2(java.lang.String)>",
},
{
"true",
"<CustomEntryPoints: void entryWithSpecifiedParam(Param1,Param1[],java.lang.String)>",
"<java.lang.String: java.lang.String toString()>",
},
{
"true",
"<CustomEntryPoints: void entryWithSpecifiedParam(Param1,Param1[],java.lang.String)>",
"<java.lang.Object: java.lang.String toString()>",
},
};

@Test
void test() {
Main.main("-pp",
"-cp", "src/test/resources/pta/entrypoint",
"--input-classes", "CustomEntryPoints",
"-a", "pta=only-app:true;implicit-entries:false;"
+ "plugins:[pascal.taie.analysis.pta.CustomEntryPointPlugin];",
"-a", "cg");
CallGraph<Invoke, JMethod> cg = World.get().getResult(CallGraphBuilder.ID);
MultiMap<JMethod, JMethod> callerCalleeRelations = cg.edges().collect(
MultiMapCollector.get(e -> e.getCallSite().getContainer(), Edge::getCallee));
ClassHierarchy hierarchy = World.get().getClassHierarchy();
for (String[] callerCalleeRelation : CALLER_CALLEE_RELATIONS) {
boolean reachable = Boolean.parseBoolean(callerCalleeRelation[0]);
JMethod caller = hierarchy.getMethod(callerCalleeRelation[1]);
JMethod callee = hierarchy.getMethod(callerCalleeRelation[2]);
assertEquals(reachable, callerCalleeRelations.contains(caller, callee),
caller + " -> " + callee);
}
}

}
80 changes: 80 additions & 0 deletions src/test/resources/pta/entrypoint/CustomEntryPoints.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
public class CustomEntryPoints {

// static entrypoint with empty parameters
public static void entryWithEmptyParam(Param1 p1, Param1[] p1s) {
String s1 = p1.getS1(); // Param1.getS1 is not reachable
p1s[0].setS2(s1); // Param1.setS2 is not reachable
}

// static entrypoint with declared parameters
public static void entryWithDeclaredParam1(Param1 p1, Param1[] p1s) {
String s1 = p1.getS1(); // Param1.getS1 is reachable
p1s[0].setS2(s1); // Param1.setS2 is reachable
}

// static entrypoint with declared parameters
public static void entryWithDeclaredParam2(Param2 p2) {
String s1 = p2.getS1(); // Param2.getS1 is reachable
Param1 p1 = p2.getP1(); // p1 is not null if k >= 1
String s2 = p1.getS2(); // Param1.getS2 is reachable if k >= 2
}

// instance entrypoint with specified parameters
public void entryWithSpecifiedParam(Param1 p1, Param1[] p1s, String s) {
String s1 = p1.getS1(); // Param1.getS1 is reachable
p1s[0].setS2(s1); // Param1.setS2 is reachable
s.toString(); // String.toString is reachable
this.toString(); // Object.toString is reachable
}

}

class Param1 {

private String s1;

private String s2;

public Param1(String s1, String s2) {
this.s1 = s1;
this.s2 = s2;
}

public String getS1() {
return s1;
}

public String getS2() {
return s2;
}

public void setS1(String s1) {
this.s1 = s1;
}

public void setS2(String s2) {
this.s2 = s2;
}

}

class Param2 {

private final String s1;

private final Param1 p1;

public Param2(String s1, Param1 p1) {
this.s1 = s1;
this.p1 = p1;
}

public String getS1() {
return s1;
}

public Param1 getP1() {
return p1;
}

}

0 comments on commit c45e1c4

Please sign in to comment.