Correlating Effectiveness of Pointer Analysis Techniques with Patterns in Embedded System Code
Abstract
A pointer analysis maps the pointers in a program to the memory locations they point to. In this work, we study the effectiveness of the three flavors of pointer analysis namely flow sensitive, flow insensitive, and context sensitive analysis on seven embedded code sets used in the industry. We compare precision gain i.e., the reduction in the number of spurious memory locations pointed by a pointer in each of these settings. We found that in 90% of cases the pointer information was same in all three settings. In other cases, context sensitive analysis was 2.6% more precise than flow sensitive analysis which was 6.8% more precise than flow insensitive analysis on average. We correlate precision gain with coding patterns in the embedded systems—which we believe to be first of its kind activity.
Index Terms:
Pointer Analysis, Context Sensitivity, Flow Sensitivity, Embedded Code SetI Introduction
Embedded systems are an important part of today’s life, specific examples include—controlling devices in car, avionics in aircraft, telematic systems for traffic control, pacemakers, and control systems in nuclear reactors. In the embedded systems where safety and reliability is critical, early defect detection can prevent serious destruction. Hence, for safety critical and reactive systems the compliance checks (e.g., ISO 26262, IEC 62304, DO178B/C) have become mandatory. Ensuring this compliance using manual analysis is error prone and costly. Therefore, many compliance checks are validated using static analysis tools. Consequently, these tools have become an integral part of software development life cycle of embedded systems.
Most static analysis tools rely on a pointer analysis to get the actual memory locations pointed to by a pointer at its dereference points. If this underlying points-to information is accurate, it helps tools to gain more precision in their top level analysis [1]. This basic demand to get precise points-to information has led to the development of several pointer analysis techniques [2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]. Theoretically these techniques provide different levels of precision and scalability depending on the choice of flow and context sensitivity. In particular, a flow in-sensitive analysis does not consider the ordering of statements in a program while computing the points-to information. In contrast, the ordering of statements is considered by a flow sensitive analysis. Additionally, a context sensitive analysis considers the call sequence of functions while computing the points-to information along with the ordering of statements within the functions. In general, it is assumed that precision increases when we move from flow insensitive analysis to flow sensitive analysis to context sensitive analysis, while scalability decreases in the same order.
We have developed a static analysis tool [13] to detect bugs like integer overflow-underflow, division by zero, and array index out of bound. While analyzing few embedded industry code sets, we failed to see significant improvement in the precision of the tool when using context sensitive pointer analysis in place of flow sensitive analysis. On further investigation, we found that there was no significant difference in precision of the points-to information itself. This lead to the question “Is this behavior peculiar to the code sets we were analyzing, or does it hold in most embedded code sets?”. To resolve this, we performed experiments and compared precision of the three pointer analysis techniques—flow sensitive, flow insensitive, and context sensitive —on seven diverse embedded industry code sets.
Our results show that on average in 90% cases all three analyses (mentioned in the previous paragraph) had equal precision. Moreover, these equal precision cases varied from 76% to 100% on different code sets. In particular, we found that the relative gain in precision is not only dependent on the technique but is also dependent on the code. In this paper, we detail the observed differences in precision based on code pattern and correlate the two.
Given that pointer analysis has been an active area of research for several years, similar studies exist in the literature [14, 15, 16, 17, 1, 18, 19]. However, we did not find any case study that targets embedded code sets used in industry, and reasons about the difference in precision based on patterns in embedded code. Mainly because embedded industry code sets are not openly available. We believe such case studies play a key part in designing highly targeted analysis that are more effective than general ones. The need for such targeted analysis has been reiterated and discussed [5, 14, 6, 20] several times.
The main contributions of this paper are:
-
•
Comparison of three pointer analysis techniques on seven diverse embedded industry codes, ranging in size from 3 KLOC to 59 KLOC.
-
•
Detailed analysis of correlation between embedded code patterns and pointer analysis effectiveness.
II Background
In this section, we explain the model used and the pointer analysis techniques that we compared.
II-A Model And Abstraction
We model our approaches for the pointer analysis as applicable to programs. In , any modification of the points-to information of a pointer can be realized from the following statements: address-of (p=&a), copy (p=q), load (p=*q), and store (*p=q). Henceforth, we call such statements as PtrAssignments.
In , we allocate heap memory using either malloc, calloc, or alloc. Here, we abstract heap by callsite i.e., we do not distinguish between different heap allocations that can happen by same allocation call (for example in presence of loops or recursion). In particular, a heap allocation call is abstractly represented by the line number of the allocation call in the program, for example, the memory allocation assignment “ptr = malloc” is modeled as “ptr = &Heap”, where #line is the line number of the assignment. Moreover, an array is considered as a monolithic scalar entity, where we do not distinguish between different elements of the same array. Next, we disassemble the aggregate types to their component fields (field-sensitive). Further, uninitialized global declarations are considered to be initialized to 0 (null), and uninitialized locals are initialized to special value unknown.
We represent the application being analyzed by a directed graph called the Program Call Graph (PCG) with the application’s entry function (typically main) as the start node of the graph. Additionally each node in the graph represents a function in the application and directed edges are present between caller and corresponding called functions. Moreover, each function’s body is represented by a separate control flow graph (CFG).
We use the following representation for points-to information. At each program point, we store the set of possible memory locations pointed by each pointer i.e., let be set of all pointers in the program, and be set of all possible memory locations that could be pointed to in the program then, PointsToInfo (PI):
II-B Approach Description
We now describe the details of flow insensitive, flow sensitive, and context sensitive pointer analysis below.
Flow Insensitive Pointer Analysis: Here, flow insensitive analysis refers to flow and context insensitive analysis. In this, we perform Anderson’s [3] flow insensitive pointer analysis iteratively, where all PtrAssignments in the program are iteratively solved and a directed Points-to graph is constructed. The graph contains two types of nodes namely pointer nodes (PtrN) and pointee nodes (PtdN). A PtrN represents a pointer in the program, whereas PtdN represents a set of pointees (i.e., a set of memory locations). To resolve multilevel pointers, we iterate until the graph reaches a fixed point i.e., the information at each node does not change.
Flow Sensitive Pointer Analysis: Here, flow sensitive analysis refers to flow sensitive and context insensitive analysis. In this, we use functional approach of inter-procedural analysis [21] for computing points-to information. The approach involves two phases. In the first phase, we iterate over all functions in the PCG and create a summary for each of the functions. In the second phase, we analyze each function to compute the following two information for all nodes n in the CFG of the function until a fix-point (saturation) is reached: let INn and OUTn represent the program points just before and after the execution of a node , and pred(n) be the set of immediate predecessors of node in the CFG of the function. INn for the start node of the CFG is a special value called Boundary.
INn | (1) | |||
OUTn | (2) |
Table I summarizes the GEN and KILL information for each of the PtrAssignments node type. The information at the exit node of the CFG of a function is called the summary of the function.
A function boundary represents the information at the IN of start node of the function CFG. The boundary of the entry function (typically main) is computed by processing all the global declarations in the program. For other functions the initial boundary value is a special value called Top (). When the call node of a function is encountered then the meet (typically union) of ’s existing boundary value and the value present in IN is set as the new boundary of . The function summary of (that has GEN and KILL information) is used to compute OUT. We keep iterating over functions in the PCG as long as there is change in either the information at any node, the function boundary, or the summary of any function.
Node n |
|
|||||||
---|---|---|---|---|---|---|---|---|
|
|
|||||||
|
|
|||||||
|
|
|||||||
|
|
Context Sensitive Pointer Analysis: Here, the context sensitive analysis refers to the flow and context sensitive analysis. Additionally, a calling context refers to the data flow value at the IN of a call point of a function. Here, we solve every called function separately for each of its distinct calling context. Two calling contexts of a function are distinct if they have different data flow values [22]. We compute the function summary for each distinct context and store function, context, summary tuple. We start solving from the entry function with all the global initializations as its context. While solving any function , when a call node c is encountered, IN is used to compute context ctx of the called function . If tuple , ctx, sum exists then sum is used to compute Out, else ’s solving is suspended till the summary is computed for w.r.t context ctx. We iterate over the PCG as long as either new contexts are added/updated or for any context, information changes at any node or a function summary changes.
III Experimental Setup
We performed our experiments on an intel core i-7, 8 GB RAM, windows 64 bit machine. We implemented the three pointer analysis techniques in our inhouse TCS Embedded Code Analyzer(TCS ECA) Tool [13]. In this, we included seven diverse proprietary embedded code sets from the industry. These code sets were developed by different manufacturers from the automotive industry, different teams within different organizations. Few of these code sets are safety-critical systems. Table II presents the characteristics of these code sets. In particular, the size of code sets range from 3 to 59 KLOC, while the number of functions are in the range of 30 to 790. Only one of the code set (i.e., CAN1) contains heap allocation calls, and 3 code sets have 2 to 25 function pointer dereferences. Overall pointer dereference instances range from 52 to 3047 across code sets.
#Nodes | #Pointer Assignment Nodes | ||||||||||||||||||||||||||||||
Initialization | Assignment |
|
|
|
|
|
|
||||||||||||||||||||||||
Application |
KLoC |
PCG | CFG |
Local |
Global |
Local |
|
||||||||||||||||||||||||
SMCARD | 3 | 48 | 1929 | 2 | 37 | 0 | 254 | 0 | 0 | 23 | 25 | 52 | 52 | ||||||||||||||||||
NavPS | 33 | 66 | 1956 | 1 | 86 | 0 | 21 | 0 | 0 | 47 | 19 | 426 | 419 | ||||||||||||||||||
ATCM | 18 | 235 | 4146 | 0 | 31 | 89 | 43 | 0 | 11 | 143 | 92 | 552 | 351 | ||||||||||||||||||
CAN1 | 30 | 30 | 1749 | 37 | 135 | 140 | 286 | 26 | 2 | 23 | 7 | 627 | 462 | ||||||||||||||||||
BTCM | 40 | 923 | 27588 | 28 | 242 | 84 | 395 | 0 | 0 | 855 | 68 | 3047 | 2870 | ||||||||||||||||||
BCM | 59 | 790 | 23565 | 2 | 377 | 75 | 184 | 0 | 25 | 607 | 183 | 178 | 121 | ||||||||||||||||||
CAN2 | 37 | 125 | 2640 | 6 | 36 | 26 | 39 | 0 | 0 | 109 | 16 | 520 | 351 |
We treat each level of a multi-level pointer dereference as a different Point of Interest (PoI). Subsequently, for each PoI where a pointer ptr is dereferenced, we compute points-to information ptdSet corresponding to the three pointer analyses:
-
•
Flow Insensitive Information (FIS) = ptdSetFIS
-
•
Flow Sensitive Information (FS) = ptdSetFS
-
•
Context Sensitive Information (CS) = { ptdSetCSi }, where i denotes the information corresponding to the ith context.
A context sensitive information for ptr is considered be more precise, if at least one context has more precise information compared to the corresponding FS or FIS information at the point (this includes the added precision when the client analysis can enquire points-to information in specific contexts). We compare FS, FIS, and CS informations for each ptr and bucket the judgment in one of the following pointee-relation classes:
-
•
: points-to information of ptr is same in FIS, FS, and CS i.e.,
-
•
: points-to information of ptr in: 1) CS is more precise than FS, and 2) FS is more precise than FIS i.e.,
-
•
: points-to information of ptr is same in FS and FIS, and is less precise than CS i.e.,
-
•
: points-to information of ptr in CS and FS is same, and is more precise than FIS i.e.,
Observe that the above cases are mutually exclusive and exhaustive (i.e., cover all possible scenarios). More specifically, the result of FIS is an over-approximaton of result of FS which is an over-approximation of CS (since CS is flow and context sensitive). Therefore, cases where FIS is more precise than FS, or FS is more precise than CS are not possible.
IV Results and Discussion
Table III presents the results of our experiments, and summarizes the distribution of the PoI’s into pointee-relation classes. More specifically, in 5 out of 7 applications, more than 90% PoI had equal precision (i.e., FIS=FS=CS), for rest two application (ATCM and CAN1) there was a precision gain of 16% and 20% while moving from flow insensitive to flow sensitive analysis.
We analyzed the coding patterns, the type of pointer (constant, formal, global or local), and the type of the pointer assignments (single assignment, multiple assignment) affecting the precision. Below we describe the concrete % of occurrence of each of these patterns that led to these results.
1. We observed that on average in 90.5% cases the flow sensitive, the flow insensitive, and the context sensitive analysis gave the same results. This result can be explained by ubiquitous presence of the following code patterns in the code we analyzed.
-
•
Constant Pointer: In this case, a pointer is declared as constant pointer and is assigned a memory address in declaration. For such case, it is intuitive that FIS=FS=CS. In the embedded code sets, information is read and written to hard coded memory addresses through constant pointers or via dereference of constant address directly. These cases contributed on average 33.7% POIs in FIS=FS=CS cases, and 31% POIs in overall cases.
-
•
Formal Pointer: A formal pointer refers to a pointer declared as a function parameter. 30.7% cases of FIS=FS=CS category are of the formal pointer dereferences. In this, we observed that the formal pointers are not reassigned in the procedure. Consequently, the points-to information for the flow insensitive and the flow sensitive analysis is same (i.e., FIS=FS) for such pointer dereferences within the function.
Further, context sensitive analysis also does not add any value in these cases because the formal pointer is assigned the same actual parameter at all the call sites of the function. This results in the same points-to information in any context as that of FS and FIS. 4 out of 7 applications depict this behavior where formals are assigned to the same variable at all call sites. Interestingly, in many procedures formal pointers are used to manipulate the values of particular global variables/arrays through pointer mimicking the setter/getter functions in Java.
-
•
Single Assigned Pointers: pointers are assigned only once in the entire program and the assignment occurs before the dereference point, so points-to information is same in FIS, FS, and CS. We observed 16.2% cases among the FIS=FS=CS cases are of this type.
-
•
Multi Assigned Pointers: We observed that in 19.4% cases among FIS=FS=CS cases were under this category, where a pointer is assigned multiple values at different points and all definitions reach to the dereference point through at least one path which results in FIS=FS=CS.
Total PoIs | #PoIs(%) | |||||||
---|---|---|---|---|---|---|---|---|
|
|
|
||||||
SMCARD | 52 | 52 (100) | 0 (0) | 0 (0) | ||||
NavPS | 426 | 424 (99.5) | 2 (0.5) | 0 (0) | ||||
ATCM | 552 | 400 (72.4) | 28 (5) | 124 (22.6) | ||||
CAN1 | 627 | 515 (82.1) | 12 (1.9) | 100 (16) | ||||
BTCM | 3047 | 2895 (95) | 150 (4.93) | 2 (0.07) | ||||
BCM | 178 | 161 (90.4) | 11 (6.2) | 6 (3.4) | ||||
CAN2 | 520 | 489 (94.1) | 0 (0) | 31 (5.9) | ||||
Average | 771.7 | 705 ( 90.52) | 29 (2.65) | 37.57 (6.83) |
Figure 1 presents the percentage of: Constant Pointer, Formal Pointer, Single Assignment, and Multiple Assignment in the individual applications. It also highlights that none of the pattern is prevalent across the applications, yet the overall impact on the precision is same.
2. This category measures cases where the flow sensitivity and the context sensitivity both add some disjoint precision to the results. Even though we expected this case to be prevalent, we found only 1 out of 5403 analyzed cases of this type. In this lone case, a formal pointer was assigned different addresses at different callsites and it was conditionally updated inside an if-then branch in the procedure after which it was dereferenced in the same procedure. The calls from multiple sites with different addresses made the context sensitive analysis more precise than FIS and FS, while the re-assignment of formal pointer— which we never saw happening anywhere else in these code sets—in the if-then branch made FS more precise than FIS for dereference in the else branch. The dearth of cases in this category can be attributed to practice of not re-assigning formal pointers in the corresponding procedures.
3. Given that we observed only 1 case of category, we can say category measures the complete impact of the context sensitivity on the precision. Here, we observed an average of 2.6% cases of this type. This indicates that context sensitivity has not added much value over a flow sensitive analysis across the code sets. One of the reason for this is that in embedded code sets, most formal pointers are used for manipulation of specific variables, meaning they will be assigned same variable at all callsites. Consequently, a context sensitive analysis over such code may not improve precision. On the other hand, we did observe improvement in 5-6% cases in applications namely ATCM, BTCM, and BCM where formal pointers were assigned different variables at different call sites, indicating context sensitive analysis’ impact is not negligible. Nevertheless, a context sensitive analysis involves significant overhead over flow sensitive analysis like maintaining contexts, separate procedure solving for each context. In such cases, it is a good idea to do a lightweight pre-analysis to anticipate the usefulness of context sensitivity before making an analysis choice.
4. Given that CS (refers to context and flow sensitive) is at least as precise as FS i.e., is infeasible case, and has occurred only once, we can say measures the complete impact of the flow sensitivity on the precision. We found 6.8% cases of this type. Among these cases 85% cases are of the following type. An uninitialized global pointer is assigned at single location before use point. Since C semantics say uninitialized global pointer is initialized to null by default, the flow insensitive points-to information for such pointers contains null along with the actual assigned address, while the flow sensitive and the context sensitive analysis contains only the assigned address because null is killed at the assignment location. Apart from this, in 11% of the cases a local pointer was initialized with null, and it was re-assigned at single location before use, giving similar result as the above 85% cases. Lastly, in the remaining 4% of the cases pointer was assigned before and after its use point resulting into difference in the flow sensitive and the flow insensitive points to information at such use point.
FIS | FS | CS | |
---|---|---|---|
SMCARD | 0.4 | 0.6 | |
NavPS | 1.14 | 3.18 | |
ATCM | 1.06 | 1.43 | |
CAN1 | 1.14 | 1.81 | |
BTCM | 3 | 6 | |
BCM | 0.6 | 1.1 | |
CAN2 | 0.87 | 1.07 |
IV-A Analysis Time
Table IV shows the time taken by the three analyses on different code sets. In particular, the FIS analysis took 1-6 micro seconds to complete while a flow sensitive and context sensitive analysis took up to 3 and 6 seconds to complete respectively. In comparison, the context sensitive analysis took up to 200% more time than flow sensitive analysis. On the other hand, a flow sensitive analysis time was more than flow insensitive analysis by a magnitude of .
IV-B Result Summary and Future Directions
Our code sets showcased varied amount of precision gain due to the differences in the coding constructs used. In particular, the dereference of constant pointers, and the pointers which are assigned the same pointees from different locations resulted in , these cases were dominant in all the embedded code sets. Moreover, different assignments to formal pointers contributed to the bucket. Finally, most cases where was due to standard where uninitialized pointers are default assigned null . Having said that, if one has to implement a pointer analysis technique then it will be advisable to keep these trends in mind and understand the code for which the analysis has to be applied, and then make a choice of technique as per one’s requirement.
More specifically, one can write a pre-analysis that scans the code to quantify the presence of the above patterns in the code. Subsequently, the output of pre-analysis can be used to automatically decide which of the three analyses to do on the code. For instance, if the code contains no cases where a formal pointer is assigned more than one variables then doing context sensitive analysis is not useful in such case.
V Related Work
Das et al. [23] showcased that the flow sensitive analysis provided almost the same level of precision on 95% cases, they showed this for large open source applications of uptill 2MLoC. Their conclusion on precision gain has been in coherence with Ruf [17], Foster [24]. Ruf et al. [17] presented an empirical study of the flow sensitive and the context sensitive analysis. They showed with caution that there can be no improvement in the precision at the dereference locations. We have shown a similar result on the embedded code sets. In our work, we also presented a reasoning based on the code patterns in the embedded code sets which was not done in the earlier work.
Engblom et al. [19] studied embedded system’s static property, they aimed to improve and guide development of worst case execution time analysis. Whereas, our focus is on pointer usage and its assignment pattern that affects the precision of pointer analysis. They also concluded that pointer analysis is necessary to obtain good results on embedded code. Liang et al. [25] and Lhotak et al. [15] evaluated the effectiveness of the context sensitive points-to analysis on the Java programs. Their results show that the context sensitivity increases the precision for some benchmarks, and the context sensitive heap abstraction is important for precision. Empirical studies by Hind et al. [16, 18] focused on comparing the flow insensitive and the flow sensitive analysis with different tuning, both studies concluded that for most applications the two type of analysis didn’t show the expected precision gain difference. They gave intuitive reasoning for such behavior, whereas we had extended it to the code level reasoning making it more concrete.
VI Conclusion
This work described an empirical study carried out to evaluate the effectiveness of three different pointer analysis techniques on seven diverse embedded code sets used in industry. We found in 90% cases the flow insensitive analysis is as precise as flow and context sensitive analysis. Subsequently, we highlighted the correlation between the precision gain and the code constructs used in the industry. We also discussed how the results of this study can be used to design targeted and effective pointer analyses for embedded industry code sets.
References
- [1] M. Shapiro and S. Horwitz, “The effects of the precision of pointer analysis,” in Static Analysis, pp. 16–34, Springer, 1997.
- [2] R. P. Wilson and M. S. Lam, Efficient context-sensitive pointer analysis for C programs, vol. 30. ACM, 1995.
- [3] L. O. Andersen, Program analysis and specialization for the C programming language. PhD thesis, University of Cophenhagen, 1994.
- [4] B. Hardekopf and C. Lin, “Semi-sparse flow-sensitive pointer analysis,” in ACM SIGPLAN Notices, vol. 44, pp. 226–238, ACM, 2009.
- [5] S. Z. Guyer and C. Lin, “Client-driven pointer analysis,” in Static Analysis, pp. 214–236, Springer, 2003.
- [6] M. Sridharan, D. Gopan, L. Shan, and R. Bodík, “Demand-driven points-to analysis for java,” in ACM SIGPLAN Notices, vol. 40, pp. 59–76, ACM, 2005.
- [7] B. Steensgaard, “Points-to analysis in almost linear time,” in Proceedings of the 23rd ACM SIGPLAN-SIGACT symposium on Principles of programming languages, pp. 32–41, ACM, 1996.
- [8] B. Hardekopf and C. Lin, “The ant and the grasshopper: fast and accurate pointer analysis for millions of lines of code,” in ACM SIGPLAN Notices, vol. 42, pp. 290–299, ACM, 2007.
- [9] D. J. Pearce, P. H. Kelly, and C. Hankin, “Efficient field-sensitive pointer analysis of c,” ACM Transactions on Programming Languages and Systems (TOPLAS), vol. 30, no. 1, p. 4, 2007.
- [10] E. M. Nystrom, H.-S. Kim, and W. H. Wen-mei, “Bottom-up and top-down context-sensitive summary-based pointer analysis,” in Static Analysis, pp. 165–180, Springer, 2004.
- [11] B. Hardekopf and C. Lin, “Flow-sensitive pointer analysis for millions of lines of code,” in Code Generation and Optimization (CGO), 2011 9th Annual IEEE/ACM International Symposium on, pp. 289–298, IEEE, 2011.
- [12] H. Yu, J. Xue, W. Huo, X. Feng, and Z. Zhang, “Level by level: making flow-and context-sensitive pointer analysis scalable for millions of lines of code,” in Proceedings of the 8th annual IEEE/ACM international symposium on Code generation and optimization, pp. 218–229, ACM, 2010.
- [13]
- [14] M. Hind, “Pointer analysis: haven’t we solved this problem yet?,” in Proceedings of the 2001 ACM SIGPLAN-SIGSOFT workshop on Program analysis for software tools and engineering, pp. 54–61, ACM, 2001.
- [15] O. Lhoták and L. Hendren, “Context-sensitive points-to analysis: is it worth it?,” in Compiler Construction, pp. 47–64, Springer, 2006.
- [16] M. Hind and A. Pioli, “Evaluating the effectiveness of pointer alias analyses,” Science of Computer Programming, vol. 39, no. 1, pp. 31–55, 2001.
- [17] E. Ruf, “Context-insensitive alias analysis reconsidered,” ACM SIGPLAN Notices, vol. 30, no. 6, pp. 13–22, 1995.
- [18] M. Hind and A. Pioli, Assessing the effects of flow-sensitivity on pointer alias analyses. Springer, 1998.
- [19] J. Engblom, “Static properties of commercial embedded real-time programs, and their implication for worst-case execution time analysis,” in Real-Time Technology and Applications Symposium, 1999. Proceedings of the Fifth IEEE, pp. 46–55, IEEE, 1999.
- [20] S. Z. Guyer and C. Lin, “Error checking with client-driven pointer analysis,” Science of Computer Programming, vol. 58, no. 1, pp. 83–114, 2005.
- [21] M. Sharir, A. Pnueli, et al., Two approaches to interprocedural data flow analysis. New York University. Courant Institute of Mathematical Sciences …, 1978.
- [22] R. Padhye and U. P. Khedker, “Interprocedural data flow analysis in soot using value contexts,” in Proceedings of the 2Nd ACM SIGPLAN International Workshop on State Of the Art in Java Program Analysis, pp. 31–36, ACM, 2013.
- [23] M. Das, B. Liblit, M. Fähndrich, and J. Rehof, “Estimating the impact of scalable pointer analysis on optimization,” in Static Analysis, pp. 260–278, Springer, 2001.
- [24] J. S. Foster, M. Fähndrich, and A. Aiken, “Polymorphic versus monomorphic flow-insensitive points-to analysis for c,” in Static Analysis, pp. 175–198, Springer, 2000.
- [25] D. Liang, M. Pennings, and M. J. Harrold, “Evaluating the impact of context-sensitivity on andersen’s algorithm for java programs,” in ACM SIGSOFT Software Engineering Notes, vol. 31, pp. 6–12, ACM, 2005.