001: package soot.jimple.toolkits.thread;
002:
003: import soot.*;
004:
005: import java.util.*;
006: import soot.jimple.toolkits.infoflow.*;
007: import soot.jimple.toolkits.thread.mhp.*;
008: import soot.jimple.*;
009:
010: // ThreadLocalObjectsAnalysis written by Richard L. Halpert, 2007-03-05
011: // Runs LocalObjectsAnalysis for the special case where we want to know
012: // if a reference is local to all threads from which it is reached.
013:
014: public class ThreadLocalObjectsAnalysis extends LocalObjectsAnalysis
015: implements IThreadLocalObjectsAnalysis {
016: MhpTester mhp;
017: List<AbstractRuntimeThread> threads;
018: InfoFlowAnalysis primitiveDfa;
019: static boolean printDebug = false;
020:
021: Map valueCache;
022: Map fieldCache;
023: Map invokeCache;
024:
025: public ThreadLocalObjectsAnalysis(MhpTester mhp) // must include main class
026: {
027: super (new InfoFlowAnalysis(false, true, printDebug)); // ref-only, with inner fields
028: this .mhp = mhp;
029: this .threads = mhp.getThreads();
030: this .primitiveDfa = new InfoFlowAnalysis(true, true, printDebug); // ref+primitive, with inner fields
031:
032: valueCache = new HashMap();
033: fieldCache = new HashMap();
034: invokeCache = new HashMap();
035: }
036:
037: // Forces the majority of computation to take place immediately, rather than on-demand
038: // might occasionally compute more than is necessary
039: public void precompute() {
040: for (AbstractRuntimeThread thread : threads) {
041: for (Object item : thread.getRunMethods()) {
042: SootMethod runMethod = (SootMethod) item;
043: if (runMethod.getDeclaringClass().isApplicationClass())
044: getClassLocalObjectsAnalysis(runMethod
045: .getDeclaringClass());
046: }
047: }
048: }
049:
050: // override
051: protected ClassLocalObjectsAnalysis newClassLocalObjectsAnalysis(
052: LocalObjectsAnalysis loa, InfoFlowAnalysis dfa,
053: UseFinder uf, SootClass sc) {
054: // find the right run methods to use for threads of type sc
055: List<SootMethod> runMethods = new ArrayList<SootMethod>();
056: Iterator<AbstractRuntimeThread> threadsIt = threads.iterator();
057: while (threadsIt.hasNext()) {
058: AbstractRuntimeThread thread = threadsIt.next();
059: Iterator<Object> runMethodsIt = thread.getRunMethods()
060: .iterator();
061: while (runMethodsIt.hasNext()) {
062: SootMethod runMethod = (SootMethod) runMethodsIt.next();
063: if (runMethod.getDeclaringClass() == sc)
064: runMethods.add(runMethod);
065: }
066: }
067:
068: return new ClassLocalObjectsAnalysis(loa, dfa, primitiveDfa,
069: uf, sc, runMethods);
070: }
071:
072: // Determines if a RefType Local or a FieldRef is Thread-Local
073: public boolean isObjectThreadLocal(Value localOrRef, SootMethod sm) {
074: if (threads.size() <= 1)
075: return true;
076: // Pair cacheKey = new Pair(new EquivalentValue(localOrRef), sm);
077: // if(valueCache.containsKey(cacheKey))
078: // {
079: // return ((Boolean) valueCache.get(cacheKey)).booleanValue();
080: // }
081:
082: if (printDebug)
083: G.v().out.println("- " + localOrRef + " in " + sm
084: + " is...");
085: for (AbstractRuntimeThread thread : mhp.getThreads()) {
086: for (Object meth : thread.getRunMethods()) {
087: SootMethod runMethod = (SootMethod) meth;
088:
089: if (runMethod.getDeclaringClass().isApplicationClass()
090: && !isObjectLocalToContext(localOrRef, sm,
091: runMethod)) {
092: if (printDebug)
093: G.v().out
094: .println(" THREAD-SHARED (simpledfa "
095: + ClassInfoFlowAnalysis.methodCount
096: + " smartdfa "
097: + SmartMethodInfoFlowAnalysis.counter
098: + " smartloa "
099: + SmartMethodLocalObjectsAnalysis.counter
100: + ")");
101: // valueCache.put(cacheKey, Boolean.FALSE);
102: // escapesThrough(localOrRef, sm);
103: return false;
104: }
105: }
106: }
107: if (printDebug)
108: G.v().out.println(" THREAD-LOCAL (simpledfa "
109: + ClassInfoFlowAnalysis.methodCount + " smartdfa "
110: + SmartMethodInfoFlowAnalysis.counter
111: + " smartloa "
112: + SmartMethodLocalObjectsAnalysis.counter + ")");// (" + localOrRef + " in " + sm + ")");
113: // valueCache.put(cacheKey, Boolean.TRUE);
114: return true;
115: }
116:
117: /*
118: public boolean isFieldThreadLocal(SootField sf, SootMethod sm) // this is kind of meaningless..., if we're looking in a particular method, we'd use isObjectThreadLocal
119: {
120: G.v().out.println("- Checking if " + sf + " in " + sm + " is thread-local");
121: Iterator threadClassesIt = threadClasses.iterator();
122: while(threadClassesIt.hasNext())
123: {
124: SootClass threadClass = (SootClass) threadClassesIt.next();
125: if(!isFieldLocalToContext(sf, sm, threadClass))
126: {
127: G.v().out.println(" THREAD-SHARED");
128: return false;
129: }
130: }
131: G.v().out.println(" THREAD-LOCAL");// (" + sf + " in " + sm + ")");
132: return true;
133: }
134: */
135:
136: public boolean hasNonThreadLocalEffects(
137: SootMethod containingMethod, InvokeExpr ie) {
138: if (threads.size() <= 1)
139: return true;
140: return true;
141: /*
142: Pair cacheKey = new Pair(new EquivalentValue(ie), containingMethod);
143: if(invokeCache.containsKey(cacheKey))
144: {
145: return ((Boolean) invokeCache.get(cacheKey)).booleanValue();
146: }
147:
148: G.v().out.print("- " + ie + " in " + containingMethod + " has ");
149: Iterator threadsIt = threads.iterator();
150: while(threadsIt.hasNext())
151: {
152: AbstractRuntimeThread thread = (AbstractRuntimeThread) threadsIt.next();
153: Iterator runMethodsIt = thread.getRunMethods().iterator();
154: while(runMethodsIt.hasNext())
155: {
156: SootMethod runMethod = (SootMethod) runMethodsIt.next();
157: if( runMethod.getDeclaringClass().isApplicationClass() &&
158: hasNonLocalEffects(containingMethod, ie, runMethod))
159: {
160: G.v().out.println("THREAD-VISIBLE (simpledfa " + ClassInfoFlowAnalysis.methodCount +
161: " smartdfa " + SmartMethodInfoFlowAnalysis.counter +
162: " smartloa " + SmartMethodLocalObjectsAnalysis.counter + ")");// (" + ie + " in " + containingMethod + ")");
163: invokeCache.put(cacheKey, Boolean.TRUE);
164: return true;
165: }
166: }
167: }
168: G.v().out.println("THREAD-PRIVATE (simpledfa " + ClassInfoFlowAnalysis.methodCount +
169: " smartdfa " + SmartMethodInfoFlowAnalysis.counter +
170: " smartloa " + SmartMethodLocalObjectsAnalysis.counter + ")");// (" + ie + " in " + containingMethod + ")");
171: invokeCache.put(cacheKey, Boolean.FALSE);
172: return false;
173: //*/
174: }
175:
176: /**
177: Returns a list of thread-shared sources and sinks.
178: Returns empty list if not actually a shared value.
179: */
180: public List escapesThrough(Value sharedValue,
181: SootMethod containingMethod) {
182: List ret = new ArrayList();
183:
184: // The containingMethod might be called from multiple threads
185: // It is possible for interestingValue to be thread-shared from some threads but not others,
186: // so we must look at each thread separately.
187: for (AbstractRuntimeThread thread : mhp.getThreads()) {
188: // Each "abstract thread" from the MHP analysis actually represents a "Thread.start()" statement that could
189: // be starting one of several different kinds of threads. We must consider each kind separately.
190: for (Object meth : thread.getRunMethods()) {
191: SootMethod runMethod = (SootMethod) meth;
192:
193: // We can only analyze application classes for TLO
194: if (runMethod.getDeclaringClass().isApplicationClass()
195: && !isObjectLocalToContext(sharedValue,
196: containingMethod, runMethod)) {
197: // This is one of the threads for which sharedValue is thread-shared
198: // so now we will look for which object it escapes through
199: ClassLocalObjectsAnalysis cloa = getClassLocalObjectsAnalysis(containingMethod
200: .getDeclaringClass());
201: CallLocalityContext clc = cloa
202: .getMergedContext(containingMethod);
203:
204: // Get the method info flow analysis object
205: SmartMethodInfoFlowAnalysis smifa = dfa
206: .getMethodInfoFlowAnalysis(containingMethod);
207:
208: // Get an IFA node for our sharedValue
209: EquivalentValue sharedValueEqVal;
210: if (sharedValue instanceof InstanceFieldRef)
211: sharedValueEqVal = InfoFlowAnalysis
212: .getNodeForFieldRef(containingMethod,
213: ((FieldRef) sharedValue)
214: .getField());
215: else
216: sharedValueEqVal = new EquivalentValue(
217: sharedValue);
218:
219: // Get the sources of our interesting value
220: List<EquivalentValue> sources = smifa
221: .sourcesOf(sharedValueEqVal);
222: for (EquivalentValue source : sources) {
223: if (source.getValue() instanceof Ref) {
224: if (clc != null
225: && !clc.isFieldLocal(source)) // (bail out if clc is null)
226: {
227: ret.add(source);
228: // System.out.println(sharedValue + " in " + containingMethod + " escapes through " + source);
229: }
230: }
231: }
232: }
233: }
234: }
235: return ret;
236: }
237: }
|