-
Notifications
You must be signed in to change notification settings - Fork 578
/
ResourceValueFrameModelingVisitor.java
195 lines (168 loc) · 6.58 KB
/
ResourceValueFrameModelingVisitor.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
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
/*
* Bytecode Analysis Framework
* Copyright (C) 2003,2004 University of Maryland
*
* This library 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 2.1 of the License, or (at your option) any later version.
*
* This library 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 this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package edu.umd.cs.findbugs.ba;
import org.apache.bcel.generic.AASTORE;
import org.apache.bcel.generic.ARETURN;
import org.apache.bcel.generic.ArrayInstruction;
import org.apache.bcel.generic.CHECKCAST;
import org.apache.bcel.generic.ConstantPoolGen;
import org.apache.bcel.generic.FieldInstruction;
import org.apache.bcel.generic.INVOKEINTERFACE;
import org.apache.bcel.generic.INVOKESPECIAL;
import org.apache.bcel.generic.INVOKESTATIC;
import org.apache.bcel.generic.INVOKEVIRTUAL;
import org.apache.bcel.generic.InstructionHandle;
import org.apache.bcel.generic.InvokeInstruction;
import org.apache.bcel.generic.PUTFIELD;
import org.apache.bcel.generic.PUTSTATIC;
public abstract class ResourceValueFrameModelingVisitor extends AbstractFrameModelingVisitor<ResourceValue, ResourceValueFrame> {
public ResourceValueFrameModelingVisitor(ConstantPoolGen cpg) {
super(cpg);
}
@Override
public ResourceValue getDefaultValue() {
return ResourceValue.notInstance();
}
/**
* Subclasses must override this to model the effect of the given
* instruction on the current frame.
*/
public abstract void transferInstruction(InstructionHandle handle, BasicBlock basicBlock) throws DataflowAnalysisException;
// Things to do:
// Automatically detect when resource instances escape:
// - putfield, putstatic
// - parameters to invoke, but subclasses may override
// - aastore; (conservative, since the dest array may not itself escape)
// - return (areturn)
private void handleFieldStore(FieldInstruction ins) {
try {
// If the resource instance is stored in a field, then it escapes
ResourceValueFrame frame = getFrame();
ResourceValue topValue = frame.getTopValue();
if (topValue.equals(ResourceValue.instance())) {
frame.setStatus(ResourceValueFrame.State.ESCAPED);
}
} catch (DataflowAnalysisException e) {
throw new InvalidBytecodeException("Stack underflow", e);
}
handleNormalInstruction(ins);
}
@Override
public void visitPUTFIELD(PUTFIELD putfield) {
handleFieldStore(putfield);
}
private void handleArrayStore(ArrayInstruction ins) {
try {
// If the resource instance is stored in an array, then we consider
// it as having escaped. This is conservative; ideally we would
// check whether this array is a field or gets passed out of the
// method.
ResourceValueFrame frame = getFrame();
ResourceValue topValue = frame.getTopValue();
if (topValue.equals(ResourceValue.instance())) {
frame.setStatus(ResourceValueFrame.State.ESCAPED);
}
} catch (DataflowAnalysisException e) {
throw new InvalidBytecodeException("Stack underflow", e);
}
handleNormalInstruction(ins);
}
@Override
public void visitAASTORE(AASTORE arr) {
handleArrayStore(arr);
}
@Override
public void visitPUTSTATIC(PUTSTATIC putstatic) {
handleFieldStore(putstatic);
}
/**
* Override this to check for methods that it is legal to pass the instance
* to without the instance escaping. By default, we consider all methods to
* be possible escape routes.
*
* @param inv
* the InvokeInstruction to which the resource instance is passed
* as an argument
* @param instanceArgNum
* the first argument the instance is passed in
*/
protected boolean instanceEscapes(InvokeInstruction inv, int instanceArgNum) {
return true;
}
private void handleInvoke(InvokeInstruction inv) {
ResourceValueFrame frame = getFrame();
int numSlots = frame.getNumSlots();
int numConsumed = getNumWordsConsumed(inv);
// See if the resource instance is passed as an argument
int instanceArgNum = -1;
for (int i = numSlots - numConsumed, argCount = 0; i < numSlots; ++i, ++argCount) {
ResourceValue value = frame.getValue(i);
if (value.equals(ResourceValue.instance())) {
instanceArgNum = argCount;
break;
}
}
if (instanceArgNum >= 0 && instanceEscapes(inv, instanceArgNum)) {
frame.setStatus(ResourceValueFrame.State.ESCAPED);
}
handleNormalInstruction(inv);
}
@Override
public void visitCHECKCAST(CHECKCAST obj) {
try {
ResourceValueFrame frame = getFrame();
ResourceValue topValue;
topValue = frame.getTopValue();
if (topValue.equals(ResourceValue.instance())) {
frame.setStatus(ResourceValueFrame.State.ESCAPED);
}
} catch (DataflowAnalysisException e) {
AnalysisContext.logError("Analysis error", e);
}
}
@Override
public void visitINVOKEVIRTUAL(INVOKEVIRTUAL inv) {
handleInvoke(inv);
}
@Override
public void visitINVOKEINTERFACE(INVOKEINTERFACE inv) {
handleInvoke(inv);
}
@Override
public void visitINVOKESPECIAL(INVOKESPECIAL inv) {
handleInvoke(inv);
}
@Override
public void visitINVOKESTATIC(INVOKESTATIC inv) {
handleInvoke(inv);
}
@Override
public void visitARETURN(ARETURN ins) {
try {
ResourceValueFrame frame = getFrame();
ResourceValue topValue = frame.getTopValue();
if (topValue.equals(ResourceValue.instance())) {
frame.setStatus(ResourceValueFrame.State.ESCAPED);
}
} catch (DataflowAnalysisException e) {
throw new InvalidBytecodeException("Stack underflow", e);
}
handleNormalInstruction(ins);
}
}