Abstractions from tests

Mayur Naik, Hongseok Yang, Ghila Castelnuovo, Mooly Sagiv
2012 SIGPLAN notices  
We present a framework for leveraging dynamic analysis to find good abstractions for static analysis. A static analysis in our framework is parametrised. Our main insight is to directly and efficiently compute from a concrete trace, a necessary condition on the parameter configurations to prove a given query, and thereby prune the space of parameter configurations that the static analysis must consider. We provide constructive algorithms for two instance analyses in our framework: a flow-and
more » ... work: a flow-and context-sensitive thread-escape analysis and a flow-and context-insensitive points-to analysis. We show the efficacy of these analyses, and our approach, on six Java programs comprising two million bytecodes: the thread-escape analysis resolves 80% of queries on average, disproving 28% and proving 52%; the points-to analysis resolves 99% of queries on average, disproving 29% and proving 70%. 1. We present a novel approach for using concrete traces in order to obtain good abstractions in certain cases for static analysis. 2. We present a formulation of a necessary condition for an abstraction to be precise enough for a given concrete trace. 3. We provide constructive algorithms to compute the necessary condition from a concrete trace for two static analyses (threadescape analysis and points-to analysis). 4. We provide empirical evidence that our approach can be efficiently implemented and that the resulting static analysis is both precise and scalable. Example In this section, we provide the reader a flavour of our approach using thread-escape analysis. The thread-escape analysis problem We introduce the thread-escape analysis problem using the example Java program in Figure 1 . Object allocation sites have unique labels h1, h2, and so on, and we elide all types. Variables u, v, and w are locals and g is a global (i.e., static field). The program is multithreaded: in each iteration of the loop, the main thread executes the statement u.start(), which calls the start() method of class java.lang.Thread, which asynchronously starts a new thread corresponding to the object pointed to by u. Thus, after the call, the main thread proceeds to the next loop iteration while the freshly started child thread runs code not shown in the figure. The graph at the top of Figures 1(a) -(c) (ignoring the dotted boxes) shows the concrete data structure created just before program position pc in any iteration i ≥ 1 of the loop. For convenience, each object is labeled with the site at which it was created (h1, h2, etc.). The clear nodes denote thread-local objects and the shaded nodes denote thread-escaping objects. An object is thread-local if it is reachable from at most one thread, and threadescaping otherwise. An object becomes reachable from multiple threads if it is assigned to a global or if the start() method of class java.lang.Thread is invoked on it: in the former case, the object becomes reachable from all threads in the program, while in the latter case, the object becomes reachable from at least the parent thread and the freshly started child thread. Moreover, any object reachable in the heap from a thread-escaping object is also thread-escaping. Finally, once an object thread-escapes, it remains thread-escaping for the rest of the execution. In our example, the statement g = new h3 which writes to global g causes the freshly created object to thread-escape (depicted by the shaded object labeled h3). Likewise, the call u.start() causes the object pointed to by u to thread-escape (depicted by the shaded object labeled h1 from an earlier iteration). Moreover, the object pointed to by w is reachable from this object in the heap via field f2; hence, that object also thread-escapes (depicted by the shaded object labeled h4 from an earlier iteration). We formulate the thread-escape analysis problem in the form of program queries. The query we focus on in our example is q local (pc, w), which is true if, whenever any thread reaches program position pc, the object pointed to by local variable w in that thread's environment is thread-local. It is easy to see that this query is true in our example: the only thread that reaches pc is the main thread, and whenever it does, w points to the object most recently created at site h4, which is thread-local (note that this object thread-escapes only after the following statement u.start() is executed). Many clients in verification, testing, optimisation, and program understanding for multi-threaded programs can benefit from answering such queries. For instance, proving our example query enables a static race detector to prove that field id is race-free. Parametrised thread-escape analysis
doi:10.1145/2103621.2103701 fatcat:hw2i7ydfyvc7xkojpvcnmoince