Skip to content

Commit 9e935c7

Browse files
minors
1 parent d644f1f commit 9e935c7

File tree

24 files changed

+3801
-0
lines changed

24 files changed

+3801
-0
lines changed
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
package pascal.taie.analysis.bugfinder.pathsensnullpointer;
2+
3+
import java.util.List;
4+
import java.util.Optional;
5+
6+
class ContainerModel {
7+
// 容器操作类型
8+
public enum OperationType {
9+
ADD, // 添加操作
10+
GET, // 获取操作
11+
}
12+
13+
record ContainerOperationInfo(String signature, OperationType type, int valueParamIndex) {}
14+
15+
// 预定义的容器操作信息
16+
private static final List<ContainerOperationInfo> CONTAINER_OPERATIONS = List.of(
17+
// List操作
18+
new ContainerOperationInfo(
19+
"<java.util.List: boolean add(java.lang.Object)>",
20+
OperationType.ADD,
21+
0
22+
),
23+
new ContainerOperationInfo(
24+
"<java.util.List: java.lang.Object get(int)>",
25+
OperationType.GET,
26+
-1
27+
),
28+
29+
// Map操作
30+
new ContainerOperationInfo(
31+
"<java.util.Map: java.lang.Object put(java.lang.Object,java.lang.Object)>",
32+
OperationType.ADD,
33+
0
34+
),
35+
new ContainerOperationInfo(
36+
"<java.util.Map: java.lang.Object get(java.lang.Object)>",
37+
OperationType.GET,
38+
-1
39+
)
40+
);
41+
42+
static Optional<ContainerOperationInfo> getOperationInfo(String signature) {
43+
return CONTAINER_OPERATIONS.stream()
44+
.filter(info -> info.signature.equals(signature))
45+
.findFirst();
46+
}
47+
}
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
package pascal.taie.analysis.bugfinder.pathsensnullpointer;
2+
3+
import org.apache.logging.log4j.LogManager;
4+
import org.apache.logging.log4j.Logger;
5+
import pascal.taie.Main;
6+
7+
import java.util.ArrayList;
8+
import java.util.Collections;
9+
import java.util.List;
10+
11+
public class NullPointerMain {
12+
private static final Logger logger = LogManager.getLogger(NullPointerMain.class);
13+
14+
/**
15+
* 运行空指针分析的主方法
16+
* @param classPath 类路径
17+
* @param mainClass 主类名
18+
* @param javaVersion Java版本(默认为8)
19+
*/
20+
public static void run(String classPath, String mainClass, String javaVersion) {
21+
List<String> argList = new ArrayList<>();
22+
logger.info("Running null pointer analysis for {}", mainClass);
23+
24+
// 添加基本参数
25+
Collections.addAll(argList, "-cp", classPath);
26+
Collections.addAll(argList, "-m", mainClass);
27+
Collections.addAll(argList, "-java", javaVersion);
28+
Collections.addAll(argList, "-scope", "APP");
29+
30+
// 添加必要的分析
31+
Collections.addAll(argList, "-a", "must-alias");
32+
Collections.addAll(argList, "-a", "non-null");
33+
Collections.addAll(argList, "-a", "icfg");
34+
Collections.addAll(argList, "-a", "side-effect");
35+
Collections.addAll(argList, "-a", "cg");
36+
Collections.addAll(argList, "-a", "null-slice");
37+
Collections.addAll(argList, "-a", "path-sens-nullpointer");
38+
Collections.addAll(argList, "-a", "nullpointer-result-processor");
39+
40+
// 配置PTA分析
41+
Collections.addAll(argList, "-a", "pta=cs:2-type;plugins:" +
42+
"[pascal.taie.analysis.bugfinder.pathsensnullpointer.NullPointerAnalysis," +
43+
"pascal.taie.analysis.pta.plugin.NumberLiteralHandler];" +
44+
"propagate-types:[reference,null,int,long,boolean];");
45+
46+
Main.main(argList.toArray(new String[0]));
47+
}
48+
49+
/**
50+
* 运行空指针分析的简化方法(使用默认Java 8)
51+
* @param classPath 类路径
52+
* @param mainClass 主类名
53+
*/
54+
public static void run(String classPath, String mainClass) {
55+
run(classPath, mainClass, "8");
56+
}
57+
58+
public static void main(String[] args) {
59+
if (args.length < 2) {
60+
logger.error("Usage: java NullPointerMain <classpath> <main-class> [java-version]");
61+
System.exit(1);
62+
}
63+
64+
String classPath = args[0];
65+
String mainClass = args[1];
66+
String javaVersion = args.length > 2 ? args[2] : "8";
67+
68+
run(classPath, mainClass, javaVersion);
69+
}
70+
}
Lines changed: 255 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,255 @@
1+
package pascal.taie.analysis.bugfinder.pathsensnullpointer;
2+
3+
import com.fasterxml.jackson.databind.ObjectMapper;
4+
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
5+
import com.fasterxml.jackson.dataformat.yaml.YAMLGenerator;
6+
import org.apache.logging.log4j.LogManager;
7+
import org.apache.logging.log4j.Logger;
8+
import pascal.taie.World;
9+
import pascal.taie.analysis.ProgramAnalysis;
10+
import pascal.taie.analysis.bugfinder.pathsensnullpointer.npanalysis.PathSensNullPointerAnalysis;
11+
import pascal.taie.analysis.graph.icfg.ICFG;
12+
import pascal.taie.analysis.graph.icfg.ICFGBuilder;
13+
import pascal.taie.config.AnalysisConfig;
14+
import pascal.taie.ir.stmt.Stmt;
15+
import pascal.taie.language.classes.JMethod;
16+
import pascal.taie.util.collection.Maps;
17+
18+
import java.io.File;
19+
import java.io.FileWriter;
20+
import java.io.IOException;
21+
import java.io.PrintStream;
22+
import java.util.ArrayList;
23+
import java.util.List;
24+
import java.util.Map;
25+
import java.util.Set;
26+
27+
/**
28+
* Process null pointer detection results and generate readable reports
29+
*/
30+
public class NullPointerResultProcessor extends ProgramAnalysis<Void> {
31+
32+
public static final String ID = "nullpointer-result-processor";
33+
34+
private static final Logger logger = LogManager.getLogger(NullPointerResultProcessor.class);
35+
36+
private static final String RESULTS_FILE_TEMPLATE = "nullpointer-results-%s.txt";
37+
38+
private static final String RESULTS_YAML_FILE_TEMPLATE = "nullpointer-results-%s.yml";
39+
40+
private static final boolean ENABLE_TEXT_OUTPUT = false;
41+
42+
private static final boolean PRINT_PROPAGATION_PATH = false;
43+
44+
public NullPointerResultProcessor(AnalysisConfig config) {
45+
super(config);
46+
}
47+
48+
@Override
49+
public Void analyze() {
50+
List<PathSensNullPointerAnalysis.NullPointerPath> results =
51+
World.get().getResult(PathSensNullPointerAnalysis.ID);
52+
List<List<Stmt>> uninitializedResult = World.get().getResult(NullPointerAnalysis.UNINITIALIZED_RESULT);
53+
Set<Stmt> containerResults = World.get().getResult(NullPointerAnalysis.CONTAINER_NULL_RESULT);
54+
String mainClassName = World.get().getMainMethod().getDeclaringClass().getName();
55+
if (ENABLE_TEXT_OUTPUT) {
56+
dumpResultsToText(results, uninitializedResult, containerResults, mainClassName);
57+
}
58+
59+
dumpResultsToYaml(results, uninitializedResult, containerResults, mainClassName);
60+
61+
return null;
62+
}
63+
64+
/**
65+
* Extract location information from a statement
66+
* @return Map containing class name, method name and line number
67+
*/
68+
private static Map<String, String> extractLocationInfo(Stmt stmt) {
69+
Map<String, String> location = Maps.newLinkedHashMap();
70+
ICFG<JMethod, Stmt> icfg = World.get().getResult(ICFGBuilder.ID);
71+
JMethod method = icfg.getContainingMethodOf(stmt);
72+
location.put("class", method.getDeclaringClass().getName());
73+
location.put("method", method.getSignature());
74+
location.put("line", String.valueOf(stmt.getLineNumber()));
75+
return location;
76+
}
77+
78+
private void dumpResultsToText(List<PathSensNullPointerAnalysis.NullPointerPath> results,
79+
List<List<Stmt>> uninitializedFields,
80+
Set<Stmt> containerResults,
81+
String mainClassName) {
82+
String fileName = String.format(RESULTS_FILE_TEMPLATE, mainClassName);
83+
File outFile = new File(World.get().getOptions().getOutputDir(), fileName);
84+
try (PrintStream out = new PrintStream(outFile)) {
85+
logger.info("Dumping null pointer detection results to {}", outFile.getAbsolutePath());
86+
87+
out.println("Found " + results.size() + " potential null pointer issues:");
88+
out.println();
89+
90+
for (int i = 0; i < results.size(); i++) {
91+
PathSensNullPointerAnalysis.NullPointerPath path = results.get(i);
92+
out.printf("Issue #%d (Null Pointer Dereference):%n", i + 1);
93+
94+
// Print dereference location information
95+
Map<String, String> derefLocation = extractLocationInfo(path.dereferenceSite());
96+
out.printf(" Null Pointer Dereference: Class: %s, Method: %s, Line: %s%n",
97+
derefLocation.get("class"), derefLocation.get("method"), derefLocation.get("line"));
98+
99+
// Print null value source location information
100+
Map<String, String> nullLocation = extractLocationInfo(path.nullSourceSite());
101+
out.printf(" Null Value Source: Class: %s, Method: %s, Line: %s%n",
102+
nullLocation.get("class"), nullLocation.get("method"), nullLocation.get("line"));
103+
104+
if (PRINT_PROPAGATION_PATH) {
105+
out.println(" Propagation Path:");
106+
for (Stmt stmt : path.path()) {
107+
Map<String, String> pathLocation = extractLocationInfo(stmt);
108+
out.printf(" [%s:%s:%s] %s%n",
109+
pathLocation.get("class"),
110+
pathLocation.get("method"),
111+
pathLocation.get("line"),
112+
stmt);
113+
}
114+
}
115+
out.println();
116+
}
117+
118+
if (uninitializedFields != null && !uninitializedFields.isEmpty()) {
119+
out.println("Found " + uninitializedFields.size() + " potential uninitialized field issues:");
120+
out.println();
121+
for (int i = 0; i < uninitializedFields.size(); i++) {
122+
Stmt stmt = uninitializedFields.get(i).get(0);
123+
Map<String, String> location = extractLocationInfo(stmt);
124+
out.printf("Issue #%d (Uninitialized Field): Class: %s, Method: %s, Line: %s%n",
125+
i + 1, location.get("class"), location.get("method"), location.get("line"));
126+
out.printf(" Statement: %s%n", stmt);
127+
out.println();
128+
}
129+
}
130+
131+
if (containerResults != null && !containerResults.isEmpty()) {
132+
out.println("Found " + containerResults.size() + " potential null container access issues:");
133+
out.println();
134+
int i = 0;
135+
for (Stmt stmt : containerResults) {
136+
Map<String, String> location = extractLocationInfo(stmt);
137+
out.printf("Issue #%d (Null Container Access): Class: %s, Method: %s, Line: %s%n",
138+
i + 1, location.get("class"), location.get("method"), location.get("line"));
139+
out.printf(" Statement: %s%n", stmt);
140+
out.println();
141+
i++;
142+
}
143+
}
144+
145+
} catch (IOException e) {
146+
logger.error("Failed to open output file {}", outFile);
147+
}
148+
}
149+
150+
private void dumpResultsToYaml(List<PathSensNullPointerAnalysis.NullPointerPath> results,
151+
List<List<Stmt>> uninitializedFields,
152+
Set<Stmt> containerResults,
153+
String mainClassName) {
154+
String fileName = String.format(RESULTS_YAML_FILE_TEMPLATE, mainClassName);
155+
File outFile = new File(World.get().getOptions().getOutputDir(), fileName);
156+
logger.info("Dumping null pointer detection results in YAML format to {}", outFile.getAbsolutePath());
157+
158+
Map<String, Object> dumpData = Maps.newLinkedHashMap();
159+
160+
// Process Null Pointer Dereference issues
161+
List<Map<String, Object>> nullPointerIssues = new ArrayList<>();
162+
for (int i = 0; i < results.size(); i++) {
163+
PathSensNullPointerAnalysis.NullPointerPath path = results.get(i);
164+
Map<String, Object> result = Maps.newLinkedHashMap();
165+
166+
result.put("issue-type", "Null Pointer Dereference");
167+
result.put("issue-number", i + 1);
168+
169+
// Add dereference location information
170+
Map<String, String> derefLocation = extractLocationInfo(path.dereferenceSite());
171+
Map<String, Object> derefInfo = Maps.newLinkedHashMap();
172+
derefInfo.put("class", derefLocation.get("class"));
173+
derefInfo.put("method", derefLocation.get("method"));
174+
derefInfo.put("line", derefLocation.get("line"));
175+
derefInfo.put("statement", path.dereferenceSite().toString());
176+
result.put("dereference-site", derefInfo);
177+
178+
// Add null value source location information
179+
Map<String, String> nullLocation = extractLocationInfo(path.nullSourceSite());
180+
Map<String, Object> nullInfo = Maps.newLinkedHashMap();
181+
nullInfo.put("class", nullLocation.get("class"));
182+
nullInfo.put("method", nullLocation.get("method"));
183+
nullInfo.put("line", nullLocation.get("line"));
184+
nullInfo.put("statement", path.nullSourceSite().toString());
185+
result.put("null-source-site", nullInfo);
186+
187+
if (PRINT_PROPAGATION_PATH) {
188+
List<Map<String, Object>> pathInfo = new ArrayList<>();
189+
for (Stmt stmt : path.path()) {
190+
Map<String, String> pathLocation = extractLocationInfo(stmt);
191+
Map<String, Object> stmtInfo = Maps.newLinkedHashMap();
192+
stmtInfo.put("class", pathLocation.get("class"));
193+
stmtInfo.put("method", pathLocation.get("method"));
194+
stmtInfo.put("line", pathLocation.get("line"));
195+
stmtInfo.put("statement", stmt.toString());
196+
pathInfo.add(stmtInfo);
197+
}
198+
result.put("propagation-path", pathInfo);
199+
}
200+
nullPointerIssues.add(result);
201+
}
202+
dumpData.put("total-null-pointer-dereference-issues", results.size());
203+
dumpData.put("null-pointer-dereference-issues", nullPointerIssues);
204+
205+
// Process Uninitialized Field issues
206+
if (uninitializedFields != null && !uninitializedFields.isEmpty()) {
207+
List<Map<String, Object>> uninitializedFieldIssues = new ArrayList<>();
208+
for (int i = 0; i < uninitializedFields.size(); i++) {
209+
Stmt stmt = uninitializedFields.get(i).get(0);
210+
Map<String, Object> issue = Maps.newLinkedHashMap();
211+
issue.put("issue-type", "Uninitialized Field");
212+
putStmt(uninitializedFieldIssues, i, stmt, issue);
213+
}
214+
dumpData.put("total-uninitialized-field-issues", uninitializedFields.size());
215+
dumpData.put("uninitialized-field-issues", uninitializedFieldIssues);
216+
}
217+
218+
// Process Null Container Access issues
219+
if (containerResults != null && !containerResults.isEmpty()) {
220+
List<Map<String, Object>> nullContainerAccessIssues = new ArrayList<>();
221+
int i = 0;
222+
for (Stmt stmt : containerResults) {
223+
Map<String, Object> issue = Maps.newLinkedHashMap();
224+
issue.put("issue-type", "Null Container Access");
225+
putStmt(nullContainerAccessIssues, i, stmt, issue);
226+
i++;
227+
}
228+
dumpData.put("total-null-container-access-issues", containerResults.size());
229+
dumpData.put("null-container-access-issues", nullContainerAccessIssues);
230+
}
231+
232+
try (FileWriter writer = new FileWriter(outFile)) {
233+
ObjectMapper mapper = new ObjectMapper(new YAMLFactory()
234+
.enable(YAMLGenerator.Feature.INDENT_ARRAYS)
235+
.enable(YAMLGenerator.Feature.ALLOW_LONG_KEYS)
236+
.enable(YAMLGenerator.Feature.INDENT_ARRAYS_WITH_INDICATOR)
237+
.disable(YAMLGenerator.Feature.WRITE_DOC_START_MARKER)
238+
.disable(YAMLGenerator.Feature.SPLIT_LINES)
239+
);
240+
mapper.writeValue(writer, dumpData);
241+
} catch (IOException e) {
242+
logger.error("Failed to open output file {}", outFile);
243+
}
244+
}
245+
246+
private void putStmt(List<Map<String, Object>> nullContainerAccessIssues, int i, Stmt stmt, Map<String, Object> issue) {
247+
issue.put("issue-number", i + 1);
248+
Map<String, String> location = extractLocationInfo(stmt);
249+
issue.put("class", location.get("class"));
250+
issue.put("method", location.get("method"));
251+
issue.put("line", location.get("line"));
252+
issue.put("statement", stmt.toString());
253+
nullContainerAccessIssues.add(issue);
254+
}
255+
}

0 commit comments

Comments
 (0)