Skip to content

Commit e3c9438

Browse files
zhangt2333lyf1290
andcommitted
Add Spring DI and WEC analysis plugin
Co-authored-by: Yufei Liang <1078652310@qq.com>
1 parent df997ad commit e3c9438

170 files changed

Lines changed: 8124 additions & 1 deletion

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
- Add a new Java frontend, which is faster and more reliable than the Soot frontend.
88
- Add option `--ssa` to make the Java frontend generate IR in SSA form.
99
- Add option `--jre-dir` to specify the JRE directory for the Java library selected by `-java`.
10+
- Add Spring DI and WEC analysis plugin.
1011

1112
### Breaking Changes
1213
- Change the default value of option `--world-builder` to

docs/en/pointer-analysis-framework.adoc

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,13 @@ For the reflective calls specified in the log file, pointer analysis will resolv
7171
Taint analysis will be enabled when this file is given.
7272
See <<taint-analysis#taint-analysis,Taint Analysis>> for more details.
7373

74+
* Spring analysis: `spring:[true|false]`
75+
** Default value: `false`
76+
** Enable the built-in Spring Framework analysis plugin.
77+
When enabled, pointer analysis models Spring dependency injection (DI) and web endpoint configuration (WEC):
78+
it collects bean definitions from configured annotations, `@Bean` methods, and XML bean configurations; models constructor, field, and method injection; collects Spring Web endpoint handlers; and adds endpoint handlers as entry points with mock parameters.
79+
The supported Spring annotations and XML tags are configured by `src/main/resources/spring-plugin-config.yaml`.
80+
7481
* Plugins: `plugins:[<pluginClass>,...]`
7582
** Default value: `[]`
7683
** Activate plugins.To enable a plugin, just add fully-qualified name of the plugin class to this list.

src/main/java/pascal/taie/analysis/graph/flowgraph/ObjectFlowGraph.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
import pascal.taie.analysis.pta.core.cs.element.ArrayIndex;
2828
import pascal.taie.analysis.pta.core.cs.element.CSVar;
2929
import pascal.taie.analysis.pta.core.cs.element.InstanceField;
30+
import pascal.taie.analysis.pta.core.cs.element.MockPointer;
3031
import pascal.taie.analysis.pta.core.cs.element.Pointer;
3132
import pascal.taie.analysis.pta.core.cs.element.StaticField;
3233
import pascal.taie.analysis.pta.core.solver.PointerFlowEdge;
@@ -78,6 +79,12 @@ public ObjectFlowGraph(PointerFlowGraph pfg,
7879
}
7980

8081
private void addPointerFlowEdge(PointerFlowEdge edge) {
82+
if (edge.source() instanceof MockPointer ||
83+
edge.target() instanceof MockPointer) {
84+
// MockPointer is an analysis-internal PFG placeholder and is not
85+
// exposed as an OFG node.
86+
return;
87+
}
8188
FlowKind kind = edge.kind();
8289
Node source = toNode(edge.source());
8390
Node target = toNode(edge.target());

src/main/java/pascal/taie/analysis/pta/PointerAnalysis.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
import pascal.taie.analysis.pta.plugin.ThreadHandler;
4343
import pascal.taie.analysis.pta.plugin.android.AndroidAnalysis;
4444
import pascal.taie.analysis.pta.plugin.exception.ExceptionAnalysis;
45+
import pascal.taie.analysis.pta.plugin.spring.SpringAnalysis;
4546
import pascal.taie.analysis.pta.plugin.invokedynamic.InvokeDynamicAnalysis;
4647
import pascal.taie.analysis.pta.plugin.invokedynamic.Java9StringConcatHandler;
4748
import pascal.taie.analysis.pta.plugin.invokedynamic.LambdaAnalysis;
@@ -159,6 +160,9 @@ private static void setPlugin(Solver solver, AnalysisOptions options) {
159160
|| !((List<String>) options.get("taint-config-providers")).isEmpty()) {
160161
plugin.addPlugin(new TaintAnalysis());
161162
}
163+
if (options.getBoolean("spring")) {
164+
plugin.addPlugin(new SpringAnalysis());
165+
}
162166
plugin.addPlugin(new ResultProcessor());
163167
// add plugins specified in options
164168
// noinspection unchecked

src/main/java/pascal/taie/analysis/pta/core/cs/element/CSManager.java

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
import pascal.taie.ir.stmt.Invoke;
2929
import pascal.taie.language.classes.JField;
3030
import pascal.taie.language.classes.JMethod;
31+
import pascal.taie.language.type.Type;
3132
import pascal.taie.util.Indexer;
3233

3334
import java.util.Collection;
@@ -74,6 +75,12 @@ public interface CSManager {
7475
*/
7576
ArrayIndex getArrayIndex(CSObj array);
7677

78+
/**
79+
* @return the corresponding MockPointer pointer for given mock allocation.
80+
*/
81+
MockPointer getMockPointer(PointerDescriptor descriptor, Object allocation,
82+
Type type);
83+
7784
/**
7885
* @return all variables (without contexts).
7986
*/
@@ -115,7 +122,8 @@ public interface CSManager {
115122
Collection<ArrayIndex> getArrayIndexes();
116123

117124
/**
118-
* @return all pointers managed by this manager.
125+
* @return all ordinary pointers managed by this manager, excluding
126+
* analysis-internal mock pointers.
119127
*/
120128
Stream<Pointer> pointers();
121129

src/main/java/pascal/taie/analysis/pta/core/cs/element/MapBasedCSManager.java

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,12 @@ public ArrayIndex getArrayIndex(CSObj array) {
7777
return ptrManager.getArrayIndex(array);
7878
}
7979

80+
@Override
81+
public MockPointer getMockPointer(PointerDescriptor descriptor,
82+
Object allocation, Type type) {
83+
return ptrManager.getMockPointer(descriptor, allocation, type);
84+
}
85+
8086
@Override
8187
public Collection<Var> getVars() {
8288
return ptrManager.getVars();
@@ -155,6 +161,13 @@ private static class PointerManager {
155161

156162
private final Map<CSObj, ArrayIndex> arrayIndexes = Maps.newMap();
157163

164+
private final Map<MockPointerKey, MockPointer> mockPointers = Maps.newMap();
165+
166+
private record MockPointerKey(PointerDescriptor descriptor,
167+
Object allocation,
168+
Type type) {
169+
}
170+
158171
/**
159172
* Counter for assigning unique indexes to Pointers.
160173
*/
@@ -180,6 +193,13 @@ private ArrayIndex getArrayIndex(CSObj array) {
180193
a -> new ArrayIndex(a, counter++));
181194
}
182195

196+
private MockPointer getMockPointer(PointerDescriptor descriptor,
197+
Object allocation, Type type) {
198+
MockPointerKey key = new MockPointerKey(descriptor, allocation, type);
199+
return mockPointers.computeIfAbsent(key,
200+
k -> new MockPointer(descriptor, allocation, type, counter++));
201+
}
202+
183203
private Collection<Var> getVars() {
184204
return vars.keySet();
185205
}
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
/*
2+
* Tai-e: A Static Analysis Framework for Java
3+
*
4+
* Copyright (C) 2022 Tian Tan <tiantan@nju.edu.cn>
5+
* Copyright (C) 2022 Yue Li <yueli@nju.edu.cn>
6+
*
7+
* This file is part of Tai-e.
8+
*
9+
* Tai-e is free software: you can redistribute it and/or modify
10+
* it under the terms of the GNU Lesser General Public License
11+
* as published by the Free Software Foundation, either version 3
12+
* of the License, or (at your option) any later version.
13+
*
14+
* Tai-e is distributed in the hope that it will be useful,but WITHOUT
15+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
16+
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General
17+
* Public License for more details.
18+
*
19+
* You should have received a copy of the GNU Lesser General Public
20+
* License along with Tai-e. If not, see <https://www.gnu.org/licenses/>.
21+
*/
22+
23+
package pascal.taie.analysis.pta.core.cs.element;
24+
25+
import pascal.taie.language.type.Type;
26+
27+
/**
28+
* A mock implementation of {@link AbstractPointer}.
29+
*/
30+
public final class MockPointer extends AbstractPointer {
31+
32+
private final PointerDescriptor descriptor;
33+
34+
private final Object allocation;
35+
36+
private final Type type;
37+
38+
MockPointer(PointerDescriptor descriptor, Object allocation, Type type,
39+
int index) {
40+
super(index);
41+
this.descriptor = descriptor;
42+
this.allocation = allocation;
43+
this.type = type;
44+
}
45+
46+
public PointerDescriptor getDescriptor() {
47+
return descriptor;
48+
}
49+
50+
public Object getAllocation() {
51+
return allocation;
52+
}
53+
54+
@Override
55+
public Type getType() {
56+
return type;
57+
}
58+
59+
@Override
60+
public String toString() {
61+
return "MockPointer{"
62+
+ descriptor.description()
63+
+ ": " + allocation
64+
+ '}';
65+
}
66+
67+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
/*
2+
* Tai-e: A Static Analysis Framework for Java
3+
*
4+
* Copyright (C) 2022 Tian Tan <tiantan@nju.edu.cn>
5+
* Copyright (C) 2022 Yue Li <yueli@nju.edu.cn>
6+
*
7+
* This file is part of Tai-e.
8+
*
9+
* Tai-e is free software: you can redistribute it and/or modify
10+
* it under the terms of the GNU Lesser General Public License
11+
* as published by the Free Software Foundation, either version 3
12+
* of the License, or (at your option) any later version.
13+
*
14+
* Tai-e is distributed in the hope that it will be useful,but WITHOUT
15+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
16+
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General
17+
* Public License for more details.
18+
*
19+
* You should have received a copy of the GNU Lesser General Public
20+
* License along with Tai-e. If not, see <https://www.gnu.org/licenses/>.
21+
*/
22+
23+
package pascal.taie.analysis.pta.core.cs.element;
24+
25+
@FunctionalInterface
26+
public interface PointerDescriptor {
27+
28+
String description();
29+
30+
}
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
/*
2+
* Tai-e: A Static Analysis Framework for Java
3+
*
4+
* Copyright (C) 2022 Tian Tan <tiantan@nju.edu.cn>
5+
* Copyright (C) 2022 Yue Li <yueli@nju.edu.cn>
6+
*
7+
* This file is part of Tai-e.
8+
*
9+
* Tai-e is free software: you can redistribute it and/or modify
10+
* it under the terms of the GNU Lesser General Public License
11+
* as published by the Free Software Foundation, either version 3
12+
* of the License, or (at your option) any later version.
13+
*
14+
* Tai-e is distributed in the hope that it will be useful,but WITHOUT
15+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
16+
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General
17+
* Public License for more details.
18+
*
19+
* You should have received a copy of the GNU Lesser General Public
20+
* License along with Tai-e. If not, see <https://www.gnu.org/licenses/>.
21+
*/
22+
23+
package pascal.taie.analysis.pta.plugin.spring;
24+
25+
import pascal.taie.World;
26+
import pascal.taie.analysis.pta.core.cs.element.CSObj;
27+
import pascal.taie.analysis.pta.core.solver.Solver;
28+
import pascal.taie.analysis.pta.plugin.CompositePlugin;
29+
import pascal.taie.util.collection.Sets;
30+
import pascal.taie.analysis.pta.plugin.spring.di.DiAnalysis;
31+
import pascal.taie.analysis.pta.plugin.spring.util.AnnotationManager;
32+
import pascal.taie.analysis.pta.plugin.spring.util.DirectoryTraverser;
33+
import pascal.taie.analysis.pta.plugin.spring.util.XmlConfiguration;
34+
import pascal.taie.analysis.pta.plugin.spring.wec.WecAnalysis;
35+
36+
import java.util.ArrayList;
37+
import java.util.List;
38+
import java.util.Set;
39+
import java.util.function.Consumer;
40+
41+
public class SpringAnalysis extends CompositePlugin {
42+
43+
private DiAnalysis diAnalysis;
44+
45+
private WecAnalysis wecAnalysis;
46+
47+
private final List<Consumer<CSObj>> pendingBeanObjListeners = new ArrayList<>();
48+
49+
/**
50+
* Registers a listener that will be notified when a new bean object is created.
51+
* Can be called before or after {@link #setSolver(Solver)}.
52+
*/
53+
public void addNewBeanObjListener(Consumer<CSObj> listener) {
54+
pendingBeanObjListeners.add(listener);
55+
}
56+
57+
@Override
58+
public void setSolver(Solver solver) {
59+
List<String> appClassPaths = World.get().getOptions().getAppClassPath();
60+
Set<String> appClassNames = Sets.newSet();
61+
appClassPaths.parallelStream()
62+
.map(DirectoryTraverser::listClasses)
63+
.forEach(classes -> {
64+
synchronized (appClassNames) {
65+
appClassNames.addAll(classes);
66+
}
67+
});
68+
69+
AnnotationManager annotationManager = new AnnotationManager(appClassNames);
70+
XmlConfiguration xmlConfiguration = new XmlConfiguration(appClassPaths);
71+
annotationManager.initialize();
72+
xmlConfiguration.initialize();
73+
74+
diAnalysis = new DiAnalysis(solver, annotationManager, xmlConfiguration);
75+
wecAnalysis = new WecAnalysis(solver, annotationManager);
76+
77+
addPlugin(diAnalysis, wecAnalysis);
78+
super.setSolver(solver);
79+
}
80+
81+
@Override
82+
public void onStart() {
83+
diAnalysis.registerNewBeanObjListener(wecAnalysis::onNewBeanObj);
84+
pendingBeanObjListeners.forEach(diAnalysis::registerNewBeanObjListener);
85+
pendingBeanObjListeners.clear();
86+
super.onStart();
87+
}
88+
89+
}

0 commit comments

Comments
 (0)