-
Notifications
You must be signed in to change notification settings - Fork 177
/
AnalysisModelPlugin.java
169 lines (155 loc) · 6.46 KB
/
AnalysisModelPlugin.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
/*
* Tai-e: A Static Analysis Framework for Java
*
* Copyright (C) 2022 Tian Tan <[email protected]>
* Copyright (C) 2022 Yue Li <[email protected]>
*
* 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.plugin.util;
import pascal.taie.analysis.pta.core.cs.context.Context;
import pascal.taie.analysis.pta.core.cs.element.CSVar;
import pascal.taie.analysis.pta.core.solver.Solver;
import pascal.taie.analysis.pta.pts.PointsToSet;
import pascal.taie.ir.exp.Var;
import pascal.taie.ir.stmt.Invoke;
import pascal.taie.ir.stmt.Stmt;
import pascal.taie.language.classes.JMethod;
import pascal.taie.language.classes.SignatureMatcher;
import pascal.taie.util.AnalysisException;
import pascal.taie.util.collection.Maps;
import pascal.taie.util.collection.MultiMap;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Map;
import java.util.stream.IntStream;
/**
* Provides common functionalities for implementing the plugins which
* model the APIs by analyzing their semantics.
* The invoke handler method (annotated by {@link InvokeHandler})
* should follow such declaration:
* public void name(Context,Invoke,(PointsToSet,)+)
*
* @see InvokeHandler
*/
public abstract class AnalysisModelPlugin extends ModelPlugin {
protected final Map<JMethod, Method> handlers = Maps.newMap();
protected final Map<JMethod, int[]> relevantVarIndexes = Maps.newMap();
protected final MultiMap<Var, Invoke> relevantVars = Maps.newMultiMap();
protected AnalysisModelPlugin(Solver solver) {
super(solver);
registerHandlers();
}
@Override
protected void registerHandler(InvokeHandler invokeHandler, Method handler) {
SignatureMatcher matcher = new SignatureMatcher(hierarchy);
for (String signature : invokeHandler.signature()) {
matcher.getMethods(signature).forEach(api -> {
if (handlers.containsKey(api)) {
throw new RuntimeException(this +
" registers multiple handlers for " +
api + " (in a Model, at most one handler" +
" can be registered for a method)");
}
handlers.put(api, validate(handler, invokeHandler));
relevantVarIndexes.put(api, invokeHandler.argIndexes());
});
}
}
/**
* Validates the declaration of invoke handler.
*/
private static Method validate(Method handler, InvokeHandler invokeHandler) {
// check handler parameter type
int nArgs = invokeHandler.argIndexes().length;
Class<?>[] paramTypes = handler.getParameterTypes();
if (paramTypes.length == 2 + nArgs
&& paramTypes[0] == Context.class
&& paramTypes[1] == Invoke.class
&& IntStream.range(2, paramTypes.length)
.allMatch(i -> paramTypes[i] == PointsToSet.class)) {
return handler;
}
throw new RuntimeException("Illegal handler declaration of " + invokeHandler +
"\nexpected: (Context,Invoke" + ",PointsToSet".repeat(nArgs) + ")" +
"\ngiven: " + handler);
}
@Override
public void onNewStmt(Stmt stmt, JMethod container) {
if (stmt instanceof Invoke invoke && !invoke.isDynamic()) {
JMethod target = invoke.getMethodRef().resolveNullable();
if (target != null) {
int[] indexes = relevantVarIndexes.get(target);
if (indexes != null) {
for (int i : indexes) {
relevantVars.put(InvokeUtils.getVar(invoke, i), invoke);
}
}
}
}
}
@Override
public void onNewPointsToSet(CSVar csVar, PointsToSet pts) {
relevantVars.get(csVar.getVar()).forEach(invoke -> {
JMethod target = invoke.getMethodRef().resolve();
Method handler = handlers.get(target);
if (handler != null) {
int[] indexes = relevantVarIndexes.get(target);
invokeHandler(handler, invoke, csVar, pts, indexes);
}
});
}
private void invokeHandler(Method handler, Invoke invoke,
CSVar csVar, PointsToSet pts, int[] indexes) {
PointsToSet[] args = getArgs(csVar, pts, invoke, indexes);
Object[] invokeArgs = new Object[2 + args.length];
invokeArgs[0] = csVar.getContext();
invokeArgs[1] = invoke;
System.arraycopy(args, 0, invokeArgs, 2, args.length);
try {
handler.invoke(this, invokeArgs);
} catch (IllegalAccessException | InvocationTargetException e) {
throw new AnalysisException(e);
}
}
/**
* For invocation r = v.foo(a0, a1, ..., an);
* when points-to set of v or any ai (0 ≤ i ≤ n) changes,
* this convenient method returns points-to sets relevant arguments.
* For case v/ai == csVar.getVar(), this method returns pts,
* otherwise, it just returns current points-to set of v/ai.
*
* @param csVar may be v or any ai.
* @param pts changed part of csVar
* @param invoke the call site which contain csVar
* @param indexes indexes of the relevant arguments
*/
private PointsToSet[] getArgs(
CSVar csVar, PointsToSet pts, Invoke invoke, int[] indexes) {
PointsToSet[] args = new PointsToSet[indexes.length];
for (int i = 0; i < args.length; ++i) {
int index = indexes[i];
Var arg = InvokeUtils.getVar(invoke, index);
if (arg.equals(csVar.getVar())) {
args[i] = pts;
} else {
CSVar csArg = csManager.getCSVar(csVar.getContext(), arg);
args[i] = solver.getPointsToSetOf(csArg);
}
}
return args;
}
}