Conference Paper

Taming Reflection -- Aiding Static Analysis in the Presence of Reflection and Custom Class Loaders

Authors:
To read the full-text of this research, you can request a copy directly from the authors.

Abstract

Static program analyses and transformations for Java face many problems when analyzing programs that use reflection or custom class loaders: How can a static analysis know which reflective calls the program will execute? How can it get hold of classes that the program loads from remote locations or even generates on the fly? And if the analysis transforms classes, how can these classes be re-inserted into a program that uses custom class loaders? In this paper, we present TamiFlex, a tool chain that oers a partial but often eective solution to these problems. With TamiFlex, programmers can use existing staticanalysis tools to produce results that are sound at least with respect to a set of recorded program runs. TamiFlex inserts runtime checks into the program that warn the user in case the program executes reflective calls that the analysis did not take into account. TamiFlex further allows programmers to re-insert oine-transformed classes into a program. We evaluate TamiFlex in two scenarios: benchmarking with the DaCapo benchmark suite and analysing large-scale interactive applications. For the latter, TamiFlex significantly improves code coverage of the static analyses, while for the former our approach even appears complete: the inserted runtime checks issue no warning. Hence, for the first time, TamiFlex enables sound static whole-program analyses on DaCapo. During this process, TamiFlex usually incurs less than 10% runtime overhead.

No full-text available

Request Full-text Paper PDF

To read the full-text of this research,
you can request a copy directly from the authors.

... We end this section by discussing the configurable parameters of our Bayesian network (Section 3.5). 13 ...
... This analysis is soundy [53], i.e., sound except for some features of Java, including exceptions and reflection (which is resolved by a dynamic analysis [13] -unsound but complete). The datarace analysis, may-happen-in-parallel analysis, and the thread-escape analysis use either or both the call-graph and the points-to information computed by the pointer analysis. ...
... 13: Scalability metrics for ranking with and without optimizations. #Clauses and #Tuples specify the size of the Bayesian network. ...
Article
Program analysis tools that statically find bugs in software still report a deluge of false alarms notwithstanding their widespread adoption. This is because they must necessarily make approximations in order to scale to large and complex programs. The focus of this dissertation is to make static program analyses more effective by guiding them towards true bugs and away from false alarms. We do this by augmenting logical program reasoning with probabilistic reasoning. We seek to overcome the incompleteness of a static analysis by associating each alarm it produces with a probability that it is a true alarm. We compute alarm probabilities by performing Bayesian inference on a probabilistic model derived from the execution of the analysis. Moreover, the probabilistic model allows us to recompute the probabilities by conditioning them on new evidence, thereby allowing to tailor the analysis to individual codebases and user needs. The alarms are ranked by the computed probabilities to mitigate the burden of inspecting false alarms. We demonstrate the effectiveness of our approach in two practical systems. In one system, we leverage user feedback to iteratively improve the alarm ranking. The system starts with an initial ranking of alarms reported by the static analysis. In each iteration, the system seeks user feedback for the top-ranked alarm. Next, it generalizes this feedback by recomputing the probabilities of all the alarms conditioned on this feedback to produce an improved ranking for the next iteration. After a few iterations, true alarms rise to the top of the ranking, thus alleviating the burden of inspecting false alarms. In the second system, we leverage the completeness of dynamic analysis that is capable of observing concrete program executions, to rank the alarms reported by the static analysis. We hypothesize that a reported alarm is at most as complete as the analysis facts it is premised upon. For each analysis fact used by the static analysis in deducing an alarm, the system seeks a probability estimate for its completeness, from a dynamic analysis. The dynamic analysis estimates this by counting the number of times it observes the analysis fact during concrete program executions. The system then uses the estimated probabilities associated with the analysis facts to infer probabilities for alarms, and ranks alarms by the inferred probabilities.
... The goal is to detect flows of sensitive information within the implementation into insecure sinks, e.g., a file in the file system or a socket [118,119,32]. While data-flow analysis tools have become very good at analyzing or approximating OO constructs such as dynamic class loading and Java reflection [120,121], one of the main problems for a precise data flow analysis is the classification of critical sources and sinks. Many tools are based on shared libraries of well-known critical sources and sinks, created manually or by machine learning [41]. ...
... Several approaches exist to support security at design-time [228,72,229], e.g., using design-time models, but also statically during implementation [230,231] and at run-time [232,233,234]. Unfortunately, few approaches cover coupling these phases so far [121,235]. Here, we have shown in the previous chapters how to couple the design time with the implementation time but did not look at the run-time, yet. ...
Chapter
Considering the integration of the individual contributions of this thesis as a holistic framework is essential for judging the feasibility and usability of the GRaViTY framework for the development of secure software systems. Therefore, we evaluate in two case studies whether the GRaViTY framework is suitable to support the development of secure software systems as intended. In this regard, we identified two objectives we focus on. First, we investigate whether the technical integration of GRaViTY allows an application of the GRaViTY approach throughout software development processes. Second, we focus on the perspective of developers and security experts working with GRaViTY. Here, we are interested in the practical usability of GRaViTY when applied to software development. Thereby, we focus more on usability as part of software development than on detailed usability in terms of software ergonomics, e.g., regarding the realized user interface. In the end, we investigate if GRaViTY can be applied to model-driven development. Altogether, we successfully applied GRaViTY as part of the two case studies.
... The goal is to detect flows of sensitive information within the implementation into insecure sinks, e.g., a file in the file system or a socket [118,119,32]. While data-flow analysis tools have become very good at analyzing or approximating OO constructs such as dynamic class loading and Java reflection [120,121], one of the main problems for a precise data flow analysis is the classification of critical sources and sinks. Many tools are based on shared libraries of well-known critical sources and sinks, created manually or by machine learning [41]. ...
... Several approaches exist to support security at design-time [228,72,229], e.g., using design-time models, but also statically during implementation [230,231] and at run-time [232,233,234]. Unfortunately, few approaches cover coupling these phases so far [121,235]. Here, we have shown in the previous chapters how to couple the design time with the implementation time but did not look at the run-time, yet. ...
Chapter
In the last decades, various concepts have been developed to support the development and maintenance of secure software systems. On the level of programming languages, concepts like Object-Orientation (OO) have been introduced to improve the structuring and reuse in programs. Those concepts have also been reflected in modeling languages like the Unified Modeling Language (UML). On both, various kinds of security and design checks have been introduced to support developers in developing secure software systems. Also, different development processes have been proposed to structure the development and make it projectable. Besides, additional concepts for giving early and constant feedback to developers have been developed to follow these processes successfully. At this point, the most prominent one is continuous integration. While there is an overlap between all of these concepts, these are only partly integrated. We give a short introduction to the enumerated concepts focusing on how the concepts contribute to the development of a secure software system and what are yet unsolved problems.
... The goal is to detect flows of sensitive information within the implementation into insecure sinks, e.g., a file in the file system or a socket [118,119,32]. While data-flow analysis tools have become very good at analyzing or approximating OO constructs such as dynamic class loading and Java reflection [120,121], one of the main problems for a precise data flow analysis is the classification of critical sources and sinks. Many tools are based on shared libraries of well-known critical sources and sinks, created manually or by machine learning [41]. ...
... Several approaches exist to support security at design-time [228,72,229], e.g., using design-time models, but also statically during implementation [230,231] and at run-time [232,233,234]. Unfortunately, few approaches cover coupling these phases so far [121,235]. Here, we have shown in the previous chapters how to couple the design time with the implementation time but did not look at the run-time, yet. ...
Book
For ensuring a software system's security, it is vital to keep up with changing security precautions, attacks, and mitigations. Although model-based development enables addressing security already at design-time, design models are often inconsistent with the implementation or among themselves. An additional burden are variants of software systems. To ensure security in this context, we present an approach based on continuous automated change propagation, allowing security experts to specify security requirements on the most suitable system representation. We automatically check all system representations against these requirements and provide security-preserving refactorings for preserving security compliance. For both, we show the application to variant-rich software systems. To support legacy systems, we allow to reverse-engineer variability-aware UML models and semi-automatically map existing design models to the implementation. Besides evaluations of the individual contributions, we demonstrate the approach in two open-source case studies, the iTrust electronics health records system and the Eclipse Secure Storage.
... Third, we have now included a discussion section to discuss the impact of timeout setting on our experiments. Except for giving 10 minutes as timeout, which has been used in the experiments of the conference version and subsequently this extension, we further repeat the experiments with different timeouts (i.e., 1,5,20,30, and 50 minutes). Our exploratory results show that 10 minutes is a reasonable timeout for applying DroidRA to analyze Android apps. ...
... Reflection, by itself, has been investigated in several works for Java applications. Most notably, Bodden et al. [20] have presented TamiFlex for aiding static analysis in the presence of reflections in Java programs. Similar to our approach, TamiFlex is implemented on top of Soot and includes a Booster module, which enriches Java programs by "materializing" reflection methods into traditional Java calls. ...
Article
Android developers heavily use reflection in their apps for legitimate reasons. However, reflection is also significantly used for hiding malicious actions. Unfortunately, current state-of-the-art static analysis tools for Android are challenged by the presence of reflective calls, which they usually ignore. Thus, the results of their security analysis, e.g., for private data leaks, are incomplete, given the measures taken by malware writers to elude static detection. We propose a new instrumentation-based approach to address this issue in a non-invasive way. Specifically, we introduce to the community a prototype tool called DroidRA, which reduces the resolution of reflective calls to a composite constant propagation problem and then leverages the COAL solver to infer the values of reflection targets. After that, it automatically instruments the app to replace reflective calls with their corresponding Java calls in a traditional paradigm. Our approach augments an app so that it can be more effectively statically analyzable, including by such static analyzers that are not reflection-aware. We evaluate DroidRA on benchmark apps as well as on real-world apps, and we demonstrate that it can indeed infer the target values of reflective calls and subsequently allow state-of-the-art tools to provide more sound and complete analysis results.
... As is the common practice, we use the popular TamiFlex [6] tool for resolving reflective calls. However, note that our proposed scheme is not restricted by the presence of reflection: given any points-to analysis approach (augmented by Tamiflex or not), our scheme can be used to generate the corresponding artwork (by the producer) and regenerate the matching points-to information (by the consumer). ...
Preprint
Full-text available
Data-flow analyses like points-to analysis can vastly improve the precision of other analyses, and help perform powerful code optimizations. However, whole-program points-to analysis of large programs tend to be expensive - both in terms of time and memory. Consequently, many compilers (both static and JIT) and program-analysis tools tend to employ faster - but more conservative - points-to analysis to improve usability. As an alternative to such trading of precision for performance, various techniques have been proposed to perform precise yet expensive fixed-point points-to analyses ahead of time in a static analyzer, store the results, and then transmit them to independent compilation/program-analysis stages that may need them. However, an underlying concern of safety affects all such techniques - can a compiler (or program analysis tool) trust the points-to analysis results generated by another compiler/tool? In this work, we address this issue of trust, while keeping the issues of performance efficiency in mind. We propose ART: Analysis-results Representation Template - a novel scheme to efficiently and concisely encode results of flow-sensitive, context-insensitive points-to analysis computed by a static analyzer for use in any independent system that may benefit from such a highly precise points-to analysis. Our scheme has two components: (i) a producer that can statically perform expensive points-to analysis and encode the same concisely. (ii) a consumer that, on receiving such encoded results, can regenerate the points-to analysis results encoded by the artwork if it is deemed safe. We demonstrate the usage of ART by implementing a producer (in Soot) and two consumers (in Soot and the Eclipse OpenJ9 JIT compiler). We evaluate our implementation over various benchmarks from the DaCapo and SPECjvm2008 suites.
... More than ten years ago, TamiFlex [10] was proposed to boost static analyzers with information dynamically gathered (thanks to instrumentation) about reflective calls. TamiFlex also introduced an instrumentation engine to insert regular method calls into apps to boost existing static analyzers. ...
Preprint
Static analysis is sound in theory, but an implementation may unsoundly fail to analyze all of a program's code. Any such omission is a serious threat to the validity of the tool's output. Our work is the first to measure the prevalence of these omissions. Previously, researchers and analysts did not know what is missed by static analysis, what sort of code is missed, or the reasons behind these omissions. To address this gap, we ran 13 static analysis tools and a dynamic analysis on 1000 Android apps. Any method in the dynamic analysis but not in a static analysis is an unsoundness. Our findings include the following. (1) Apps built around external frameworks challenge static analyzers. On average, the 13 static analysis tools failed to capture 61% of the dynamically-executed methods. (2) A high level of precision in call graph construction is a synonym for a high level of unsoundness; (3) No existing approach significantly improves static analysis soundness. This includes those specifically tailored for a given mechanism, such as DroidRA to address reflection. It also includes systematic approaches, such as EdgeMiner, capturing all callbacks in the Android framework systematically. (4) Modeling entry point methods challenges call graph construction which jeopardizes soundness.
... for parsing the conditional values and generating the partial-result evaluators. Additionally, we use TamiFlex [20] version 2.0.3 to resolve reflective calls while constructing call graphs in Soot. We have also used two small benchmarks from the Java Grande Forum (JGF) suite [21] to manually verify our results. ...
Article
Full-text available
In spite of decades of static-analysis research behind developing precise whole-program dataflow analyses, languages that use just-in-time (JIT) compilers suffer from the imprecision of resource-bound analyses local to the scope of compilation. Recent promising approaches bridge this gap by splitting the analysis into two phases: a static phase that identifies interprocedural dependencies across program elements, and a dynamic phase that resolves those dependencies to generate final analysis results. Though this approach is capable of generating precise analysis results without incurring analysis cost in JIT compilers, such “staged analyses” lack a theoretical backing. In particular, it is unclear if one could transform a general whole-program analysis (that resolves dependencies across all program elements) to a staged one that involves evaluation of statically generated partial results later. Similarly, it would be interesting if one could generate “partial-result evaluators” in a way that can also be used to argue about their correctness. In this paper, we propose a novel model of partial analysis that addresses all these points for staged (static + dynamic) compilation systems, based on the classic theory of partial evaluation. We begin by highlighting how partial evaluation and Futamura projections are used to generate specialized program interpreters. We then describe partial analysis as the process of evaluating dependencies across program elements with respect to the statically available parts of a program, resulting into partial results. Next, we devise a strategy (by deriving a novel notion of AM projections from Futamura projections) to statically generate specialized evaluators that can process partial results using dynamic dependencies, during JIT compilation. Later, we use our proposed model to straightforwardly establish the correctness and precision properties of the idea of staging, independent of the analysis under consideration. We finally extend our model to soundly handle callbacks made from Java libraries to applications. We demonstrate the applicability of our model by showcasing examples from non-trivial Java program analyses, implementing the pipeline for one of them, and also discussing future possibilities to extend the same. We believe that our contributions in formulating this theory of partial analysis will significantly extend the usage of existing partial analyzers, as well as promote the design of new ones, for and even beyond Java.
... In particular, Christensen et al30 proposed a static analysis of Java strings based on the abstraction of the control-flow graph as a context-free grammar. By relying on regular expressions, this approach is in position to track information not only on constants inside the string values like TARSIS but also to approximate ranges of possible characters such as 0j(-?[1][2][3][4][5][6][7][8][9][0-9]*) (i.e., the string representation of integer values). However, such approximation is strictly more complex and led to less efficient analyses. ...
Article
Full-text available
In this paper, we introduce Tarsis, a new abstract domain based on the abstract interpretation theory that approximates string values through finite state automata. The main novelty of Tarsis is that it works over an alphabet of strings instead of single characters. On the one hand, such an approach requires a more complex and refined definition of the lattice operators and of the abstract semantics of string operators. On the other hand, it is in position to obtain strictly more precise results than state-of-the-art approaches. We compare Tarsis both with simpler domains and with the standard automata model, targeting case studies containing standard yet challenging string manipulations. The performance gain w.r.t. the standard automata model is also assessed, measuring the speed-up gained by Tarsis. Experiments confirm that Tarsis can obtain precise results without incurring in excessive computational costs.
... Many call graph generation techniques are proposed for a variety of programming languages, e.g., Java [31,65], Python [52], JavaScript [46], C/C++ [9,43,66], Scala [47], etc. In Java, to deal with the missing edges caused by their language features, many approaches are proposed to handle language features such as reflection [14,24,37,55,60,62], foreign function interface [34], dynamic method invocation [13], serialization [53], and library call [68]. To deal with scalability issues, Ali et al. propose CGC [4] and Averroes [5] to approximate the call graph by considering application-only. ...
Preprint
Full-text available
Call graph generation is the foundation of inter-procedural static analysis. PyCG is the state-of-the-art approach for generating call graphs for Python programs. Unfortunately, PyCG does not scale to large programs when adapted to whole-program analysis where dependent libraries are also analyzed. Further, PyCG does not support demand-driven analysis where only the reachable functions from given entry functions are analyzed. Moreover, PyCG is flow-insensitive and does not fully support Python's features, hindering its accuracy. To overcome these drawbacks, we propose a scalable demand-driven approach for generating call graphs for Python programs, and implement it as a prototype tool Jarvis. Jarvis maintains an assignment graph (i.e., points-to relations between program identifiers) for each function in a program to allow reuse and improve scalability. Given a set of entry functions as the demands, Jarvis generates the call graph on-the-fly, where flow-sensitive intra-procedural analysis and inter-procedural analysis are conducted in turn. Our evaluation on a micro-benchmark of 135 small Python programs and a macro-benchmark of 6 real-world Python applications has demonstrated that Jarvis can significantly improve PyCG by at least 67% faster in time, 84% higher in precision, and at least 10% higher in recall.
... However, since some methods can be invoked reflectively for example passing the name of the method to be invoked in a variable, when a different argument is passed to a reflective call, our tool cannot identify such change. Most static analysers ignore such case [Bodden 2011]. Overcoming this limitation is beyond the scope of this thesis. ...
Thesis
Modern software can be characterized by high degree of reuse of external artefacts. Applications depend on multiple libraries and frameworks, which in turn can also depend on other libraries and frameworks. Like any other software, libraries evolve. They release new versions, often incompatible with the previous ones. This forces client applications that depend on those libraries to update their code in response to library evolution.Updating the dependencies can be a difficult and time consuming task for client developers. It involves repetitive operations and requires the knowledge about the changes that were made to the library. Knowledge that can be shared by library developers or extracted by automated tools from source code or commit history.In recent years, multiple approaches have been proposed to mine the data or apply machine learning techniques and extract knowledge about library update in forms of rules. However, most of those approaches only focus on client developers and do not consider the expertise of library developers. They consider only simple method-to-method replacements and are only designed for statically-typed programming languages.In this thesis, we address this gap in literature with five main contributions:(1) a survey of library and client developers from two industrial companies and an open-source community;(2) first detailed documentation of the Deprewriter approach and tool in Pharo which introduces deprecations that dynamically update client code with transformation rules;(3) a study of how Deprewriter was adopted by the Pharo community through the analysis of source code in Pharo~8 and a developer survey;(4) DepMiner --- a novel approach to infer the rules for Deprewriter based on the commit history of a project;(5) a generalization of DepMiner as a new holistic approach to support library developers in the task of library update.The results of the research reported in this thesis will advance the field of automated library update by exploring the perspective of library developers and the context of the dynamically-typed languages that were often overlooked in the previous studies.
... The call graph extraction tool that we use has some limitations that we inherit. In particular, handling methods called via reflection is a known problem for static analysis (Bodden et al. 2011); the call graph extraction tool does not handle these cases. A second issue is related to polymorphism, where it is impossible to know, in the absence of runtime information, which of the implementations can be called. ...
Article
Full-text available
Machine Learning for Source Code (ML4Code) is an active research field in which extensive experimentation is needed to discover how to best use source code’s richly structured information. With this in mind, we introduce JEMMA: An Extensible Java Dataset for ML4Code Applications, which is a large-scale, diverse, and high-quality dataset targeted at ML4Code. Our goal with JEMMA is to lower the barrier to entry in ML4Code by providing the building blocks to experiment with source code models and tasks. JEMMA comes with a considerable amount of pre-processed information such as metadata, representations (e.g., code tokens, ASTs, graphs), and several properties (e.g., metrics, static analysis results) for 50,000 Java projects from the 50K-C dataset, with over 1.2 million classes and over 8 million methods. JEMMA is also extensible allowing users to add new properties and representations to the dataset, and evaluate tasks on them. Thus, JEMMA becomes a workbench that researchers can use to experiment with novel representations and tasks operating on source code. To demonstrate the utility of the dataset, we also report results from two empirical studies on our data, ultimately showing that significant work lies ahead in the design of context-aware source code models that can reason over a broader network of source code entities in a software project—the very task that JEMMA is designed to help with.
... The call graph extraction tool that we use has some limitations that we inherit. In particular, handling methods called via reflection is a known problem for static analysis (Bodden et al 2011); the call graph extraction tool does not handle these cases. A second issue is related to polymorphism, where it is impossible to know, in the absence of runtime information, which of the implementations can be called. ...
Preprint
Full-text available
Machine Learning for Source Code (ML4Code) is an active research field in which extensive experimentation is needed to discover how to best use source code's richly structured information. With this in mind, we introduce JEMMA, an Extensible Java Dataset for ML4Code Applications, which is a large-scale, diverse, and high-quality dataset targeted at ML4Code. Our goal with JEMMA is to lower the barrier to entry in ML4Code by providing the building blocks to experiment with source code models and tasks. JEMMA comes with a considerable amount of pre-processed information such as metadata, representations (e.g., code tokens, ASTs, graphs), and several properties (e.g., metrics, static analysis results) for 50,000 Java projects from the 50KC dataset, with over 1.2 million classes and over 8 million methods. JEMMA is also extensible allowing users to add new properties and representations to the dataset, and evaluate tasks on them. Thus, JEMMA becomes a workbench that researchers can use to experiment with novel representations and tasks operating on source code. To demonstrate the utility of the dataset, we also report results from two empirical studies on our data, ultimately showing that significant work lies ahead in the design of context-aware source code models that can reason over a broader network of source code entities in a software project, the very task that JEMMA is designed to help with.
... All benchmarks are analyzed with a large Java library JDK 1.6 that is widely used in recent related work [22, 27-29, 31, 42, 43, 50]. All frameworks adopt the same reflection results for the same program by running the dynamic reflection analysis tool TamiFlex [8]. Time budget is set to three hours for each analysis. ...
Preprint
Full-text available
Static analysis is a mature field with applications to bug detection, security analysis, and code optimization, etc. To facilitate these applications, static analysis frameworks play an essential role by providing a series of fundamental services such as program abstraction, control flow graph construction, and points-to/alias information computation, etc. However, despite impressive progress of static analysis, and this field has seen several popular frameworks in the last decades, it is still not clear how a static analysis framework should be designed in a way that analysis developers could benefit more: for example, what a good IR (for analysis) ought to look like? What functionalities should the module of fundamental analyses provide to ease client analyses? How to develop and integrate new analysis conveniently? How to manage multiple analyses? To answer these questions, in this work, we discuss the design trade-offs for the crucial components of a static analysis framework, and argue for the most appropriate design by following the HBDC (Harnessing the Best Designs of Classics) principle: for each crucial component, we compare the design choices made for it (possibly) by different classic frameworks such as Soot, WALA, SpotBugs and Doop, and choose arguably the best one, but if none is good enough, we then propose a better design. These selected or newly proposed designs finally constitute Tai-e, a new static analysis framework for Java. Specifically, Tai-e is novel in the designs of several aspects like IR, pointer analysis and development of new analyses, etc., leading to an easy-to-learn, easy-to-use and efficient system. To our knowledge, this is the first work that systematically explores the designs and implementations of various static analysis frameworks, and we believe it provides useful materials and viewpoints for building better static analysis infrastructures.
... Our current implementation of hybrid analysis can already handle some cases of dynamic features (e.g., reflective calls with string constants). We plan to further mitigate this issue by integrating Tamiflex [38] and ACG [50] tools for systematically reasoning about dynamic features into the Cerberus toolchain. ...
Conference Paper
Full-text available
OAuth protocols have been widely adopted to simplify user authentication and service authorization for third-party applications. However, little effort has been devoted to automatically checking the security of the libraries that service providers widely use. In this paper, we formalize the OAuth specifications and security best practices, and design Cerberus, an automated static analyzer, to find logical flaws and identify vulnerabilities in the implementation of OAuth service provider libraries. To efficiently detect security violations in a large codebase of service provider implementation, Cerberus employs a query-driven algorithm for answering queries about OAuth specifications. We demonstrate the effectiveness of Cerberus by evaluating it on datasets of popular OAuth libraries with millions of downloads. Among these high-profile libraries, Cerberus has identified 47 vulnerabilities from ten classes of logical flaws, 24 of which were previously unknown. We got acknowledged by the developers of eight libraries and had three accepted CVEs.
... These features are primarily used in the core libraries. Bodden et al. [2011] looked at the usage of reflection in the Java DaCapo benchmark suite. They found that dynamic loading was triggered by the benchmark harness. ...
Article
Full-text available
Most dynamic languages allow users to turn text into code using various functions, often named eval , with language-dependent semantics. The widespread use of these reflective functions hinders static analysis and prevents compilers from performing optimizations. This paper aims to provide a better sense of why programmers use eval . Understanding why eval is used in practice is key to finding ways to mitigate its negative impact. We have reasons to believe that reflective feature usage is language and application domain-specific; we focus on data science code written in R and compare our results to previous work that analyzed web programming in JavaScript. We analyze 49,296,059 calls to eval from 240,327 scripts extracted from 15,401 R packages. We find that eval is indeed in widespread use; R’s eval is more pervasive and arguably dangerous than what was previously reported for JavaScript.
... Previous works explored certain features, such as reflection [5,17,18,26], native code [27], and Remote Method Invocation (RMI) [25]. However, as shown by Reif et al. [20,21], there is currently limited support for building call graphs handling serialization and deserialization of objects. ...
... Moreover, like most of the static analysis approaches, RAICC is subject to falsepositives. Currently, RAICC does not handle native calls, reflective calls nor dynamic class loading, though some stateof-the-art approach could be integrated [11], [28]. Besides, although inter-app communication (IAC) is performed using the same mechanisms as ICC [29], we did not investigate in this direction. ...
... Nevertheless, they do not explicitly mention solutions to dynamic generated code by eval. TamiFlex [12] also synthesizes a program at every eval call by considering the code that has been executed during some (dynamically) observed execution traces. The static analysis can then proceed with the so obtained code without eval. ...
Article
Full-text available
Dynamic languages, such as JavaScript, employ string-to-code primitives to turn dynamically generated text into executable code at run-time. These features make standard static analysis extremely hard if not impossible, because its essential data structures, i.e., the control-flow graph and the system of recursive equations associated with the program to analyze, are themselves dynamically mutating objects. Nevertheless, assembling code at run-time by manipulating strings, such as by eval in JavaScript, has been always strongly discouraged, since it is often recognized that “ eval is evil ,” leading static analyzers to not consider such statements or ignoring their effects. Unfortunately, the lack of formal approaches to analyze string-to-code statements pose a perfect habitat for malicious code, that is surely evil and do not respect good practice rules, allowing them to hide malicious intents as strings to be converted to code and making static analyses blind to the real malicious aim of the code. Hence, the need to handle string-to-code statements approximating what they can execute, and therefore allowing the analysis to continue (even in the presence of dynamically generated program statements) with an acceptable degree of precision, should be clear. To reach this goal, we propose a static analysis allowing us to collect string values and to soundly over-approximate and analyze the code potentially executed by a string-to-code statement.
... Moreover, like most of the static analysis approaches, RAICC is subject to falsepositives. Currently, RAICC does not handle native calls, reflective calls nor dynamic class loading, though some stateof-the-art approach could be integrated [11], [28]. Besides, although inter-app communication (IAC) is performed using the same mechanisms as ICC [29], we did not investigate in this direction. ...
Preprint
Inter-Component Communication (ICC) is a key mechanism in Android. It enables developers to compose rich functionalities and explore reuse within and across apps. Unfortunately, as reported by a large body of literature, ICC is rather "complex and largely unconstrained", leaving room to a lack of precision in apps modeling. To address the challenge of tracking ICCs within apps, state of the art static approaches such as Epicc, IccTA and Amandroid have focused on the documented framework ICC methods (e.g., startActivity) to build their approaches. In this work we show that ICC models inferred in these state of the art tools may actually be incomplete: the framework provides other atypical ways of performing ICCs. To address this limitation in the state of the art, we propose RAICC a static approach for modeling new ICC links and thus boosting previous analysis tasks such as ICC vulnerability detection, privacy leaks detection, malware detection, etc. We have evaluated RAICC on 20 benchmark apps, demonstrating that it improves the precision and recall of uncovered leaks in state of the art tools. We have also performed a large empirical investigation showing that Atypical ICC methods are largely used in Android apps, although not necessarily for data transfer. We also show that RAICC increases the number of ICC links found by 61.6% on a dataset of real-world malicious apps, and that RAICC enables the detection of new ICC vulnerabilities.
Article
Data-flow analyses like points-to analysis can vastly improve the precision of other analyses, and enable powerful code optimizations. However, whole-program points-to analysis of large Java programs tends to be expensive – both in terms of time and memory. Consequently, many compilers (both static and JIT) and program-analysis tools tend to employ faster – but more conservative – points-to analyses to improve usability. As an alternative to such trading of precision for performance, various techniques have been proposed to perform precise yet expensive fixed-point points-to analyses ahead of time in a static analyzer, store the results, and then transmit them to independent compilation/program-analysis stages that may need them. However, an underlying concern of safety affects all such techniques – can a compiler (or program analysis tool) trust the points-to analysis results generated by another compiler/tool? In this work, we address this issue of trust in the context of Java, while accounting for the issue of performance. We propose ART: Analysis-results Representation Template – a novel scheme to efficiently and concisely encode results of flow-sensitive, context-insensitive points-to analysis computed by a static analyzer for use in any independent system that may benefit from such a precise points-to analysis. ART also allows for fast regeneration of the encoded sound analysis results in such systems. Our scheme has two components: (i) a producer that can statically perform expensive points-to analysis and encode the same concisely, (ii) a consumer that, on receiving such encoded results (called artwork), can regenerate the points-to analysis results encoded by the artwork if it is deemed “safe”. The regeneration scheme completely avoids fixed-point computations and thus can help consumers like static analyzers and JIT compilers to obtain precise points-to information without paying a prohibitively high cost. We demonstrate the usage of ART by implementing a producer (in Soot) and two consumers (in Soot and the Eclipse OpenJ9 JIT compiler). We have evaluated our implementation over various benchmarks from the DaCapo and SPECjvm2008 suites. Our results demonstrate that using ART, a consumer can obtain precise flow-sensitive, context-insensitive points-to analysis results in less than (average) 1% of the time taken by a static analyzer to perform the same analysis, with the storage overhead of ART representing a small fraction of the program size (average around 4%).
Article
The runtimes of managed object-oriented languages such as Java allocate objects on the heap, and rely on automatic garbage collection (GC) techniques for freeing up unused objects. Most such runtimes also consist of just-in-time (JIT) compilers that optimize memory access and GC times by employing escape analysis: an object that does not escape (outlive) its allocating method can be allocated on (and freed up with) the stack frame of the corresponding method. However, in order to minimize the time spent in JIT compilation, the scope of such useful analyses is quite limited, thereby restricting their precision significantly. On the contrary, even though it is feasible to perform precise program analyses statically, it is not possible to use their results in a managed runtime without a closed-world assumption. In this paper, we propose a static+dynamic scheme that allows one to harness the results of a precise static escape analysis for allocating objects on stack, while taking care of both soundness and efficiency concerns in the runtime. Our scheme comprises of three key ideas. First, using the results of a statically performed escape analysis, it performs optimistic stack allocation during JIT compilation. Second, it handles the challenges associated with features that may invalidate the optimism, using a novel idea of dynamic heapification. Third, it uses another novel notion of stack ordering, again supported by a static analysis, to reduce the overheads associated with the checks that determine the need for heapification. The static and the runtime components of our approach are implemented in the Soot optimization framework and in the tiered infrastructure of the Eclipse OpenJ9 VM, respectively. To evaluate the benefits, we compare our scheme with the existing escape analysis and find that it succeeds in allocating a much larger number of objects on the stack. Furthermore, the enhanced stack allocation leads to a significant reduction in the number of GC cycles and brings decent performance improvements, especially suited for constrained-memory environments.
Article
Designing a whole-program static analysis requires trade-offs between precision and scalability. While a context-insensitive points-to analysis is often considered a good compromise, it still has non-linear complexity that leads to scalability problems when analyzing large applications. On the other hand, rapid type analysis scales well but lacks precision. We use saturation in a context-insensitive type-based points-to analysis to make it as scalable as a rapid type analysis, while preserving most of the precision of the points-to analysis. With saturation, the points-to analysis only propagates small points-to sets for variables. If a variable can have more values than a certain threshold, the variable and all its usages are considered saturated and no longer analyzed. Our implementation in the points-to analysis of GraalVM Native Image, a closed-world approach to build standalone binaries for Java applications, shows that saturation allows GraalVM Native Image to analyze large Java applications with hundreds of thousands of methods in less than two ‍minutes.
Article
Static program analysis for JavaScript is more difficult than for many other programming languages. One of the main reasons is the presence of dynamic property accesses that read and write object properties via dynamically computed property names. To ensure scalability and precision, existing state-of-the-art analyses for JavaScript mostly ignore these operations although it results in missed call edges and aliasing relations. We present a novel dynamic analysis technique named approximate interpretation that is designed to efficiently and fully automatically infer likely determinate facts about dynamic property accesses, in particular those that occur in complex library API initialization code, and how to use the produced information in static analysis to recover much of the abstract information that is otherwise missed. Our implementation of the technique and experiments on 141 real-world Node.js-based JavaScript applications and libraries show that the approach leads to significant improvements in call graph construction. On average the use of approximate interpretation leads to 55.1% more call edges, 21.8% more reachable functions, 17.7% more resolved call sites, and only 1.5% fewer monomorphic call sites. For 36 JavaScript projects where dynamic call graphs are available, average analysis recall is improved from 75.9% to 88.1% with a negligible reduction in precision.
Article
Object serialization and deserialization are widely used for storing and preserving objects in files, memory, or database as well as for transporting them across machines, enabling remote interaction among processes and many more. This mechanism relies on reflection, a dynamic language that introduces serious challenges for static analyses. Current state-of-the-art call graph construction algorithms do not fully support object serialization/deserialization, i.e., they are unable to uncover the callback methods that are invoked when objects are serialized and deserialized. Since call graphs are a core data structure for multiple types of analysis (e.g., vulnerability detection), an appropriate analysis cannot be performed since the call graph does not capture hidden (vulnerable) paths that occur via callback methods. In this paper, we present Seneca, an approach for handling serialization with improved soundness in the context of call graph construction. Our approach relies on taint analysis and API modeling to construct sound call graphs. We evaluated our approach with respect to soundness, precision, performance, and usefulness in detecting untrusted object deserialization vulnerabilities. Our results show that Seneca can create sound call graphs with respect to serialization features. The resulting call graphs do not incur significant runtime overhead and were shown to be useful for performing identification of vulnerable paths caused by untrusted object deserialization.
Article
Millions of users nowadays rely on their smartphones to process sensitive data through apps from various vendors and sources. Therefore, it is vital to assess these apps for security vulnerabilities and privacy violations. Information such as to which server an app connects through which protocol, and which algorithm it applies for encryption are usually encoded as variable values and arguments of API calls. However, extracting these values from an app is not trivial. The source code of an app is usually not available, and manual reverse engineering is cumbersome with binary sizes in the tens of megabytes. Current automated tools, on the other hand, cannot retrieve values that are computed at runtime through complex transformations. In this paper, we present ValDroid , a novel static analysis tool for automatically extracting the set of possible values for a given variable at a given statement in the Dalvik byte code of an Android app. We evaluate ValDroid against existing approaches (JSA, Violist, DroidRA, Harvester, BlueSeal, StringHound, IC3, COAL) on benchmarks and 794 real-world apps. ValDroid greatly outperforms existing tools. It provides an average F 1 score of more than 90%, while only requiring 0.1 seconds per value on average. For many data types including Network Connections and Dynamic Code Loading, its recall is more than twice the recall of the best existing approaches.
Article
In this paper, we introduce DebloaterX, a new approach for automatically identifying context-independent objects to debloat contexts in object-sensitive pointer analysis ( k obj). Object sensitivity achieves high precision, but its context construction mechanism combines objects with their contexts indiscriminately. This leads to a combinatorial explosion of contexts in large programs, resulting in inefficiency. Previous research has proposed a context-debloating approach that inhibits a pre-selected set of context-independent objects from forming new contexts, improving the efficiency of k obj. However, this earlier context-debloating approach under-approximates the set of context-independent objects identified, limiting performance speedups. We introduce a novel context-debloating pre-analysis approach that identifies objects as context-dependent only when they are potentially precision-critical to k obj based on three general container-usage patterns. Our research finds that objects containing no fields of ”abstract” (i.e., open) types can be analyzed context-insensitively with negligible precision loss in real-world applications. We provide clear rules and efficient algorithms to recognize these patterns, selecting more context-independent objects for better debloating. We have implemented DebloaterX in the Qilin framework and will release it as an open-source tool. Our experimental results on 12 standard Java benchmarks and real-world programs show that DebloaterX selects 92.4% of objects to be context-independent on average, enabling k obj to run significantly faster (an average of 19.3x when k = 2 and 150.2x when k = 3) and scale up to 8 more programs when k = 3, with only a negligible loss of precision (less than 0.2%). Compared to state-of-the-art alternative pre-analyses in accelerating k obj, DebloaterX outperforms Zipper significantly in both precision and efficiency and outperforms Conch (the earlier context-debloating approach) in efficiency substantially while achieving nearly the same precision.
Article
Object-sensitive pointer analysis, which separates the calling contexts of a method by its receiver objects, is known to achieve highly useful precision for object-oriented languages such as Java. Despite recent advances, all object-sensitive pointer analysis algorithms still suffer from the scalability problem due to the combinatorial explosion of contexts in large programs. In this paper, we introduce a new approach, Conch , that can be applied to debloat contexts for all object-sensitive pointer analysis algorithms, thereby improving significantly their efficiency while incurring a negligible loss of precision. Our key insight is to approximate a recently proposed set of two necessary conditions for an object in a program to be context-sensitive, i.e., context-dependent (whose precise verification is undecidable) with a set of three linearly verifiable conditions in terms of the number of edges in the pointer assignment graph (PAG) representation of the program. These three linearly verifiable conditions, which turn out to be almost always necessary in practice, are synthesized from three key observations regarding context-dependability for the objects created and used in real-world object-oriented programs. To develop a practical implementation for Conch , we introduce an IFDS-based algorithm for reasoning about object reachability in the PAG of a program, which runs linearly in terms of the number of edges in the PAG. By debloating contexts for three representative object-sensitive pointer analysis algorithms, which are applied to a set of representative Java programs, Conch can speed up these three baseline algorithms substantially at only a negligible loss of precision (less than 0.1%) with respect to several commonly used precision metrics. In addition, Conch also improves their scalability by enabling them to analyze substantially more programs to completion than before (under a time budget of 12 hours). Conch has been open-sourced (http://www.cse.unsw.edu.au/~corg/tools/conch), opening up new opportunities for other researchers and practitioners to further improve this research. To demonstrate this, we introduce one extension of Conch to accelerate further the three baselines without losing any precision, providing further insights on extending Conch to make precision-efficiency trade-offs in future research.
Chapter
Software applications often depend on external libraries and must be updated when one of those libraries releases a new version. To make this process easier, library developers try to reduce the negative effect of breaking changes by deprecating the API elements before removing them and suggesting replacements to the clients. Modern programming languages and IDEs provide powerful tools for deprecations that can reference the replacement or incorporate the rules written by library developers and use them to automatically update the client code. However, in practice library developers often miss the deprecation opportunities and fail to document the deprecations. In this work, we propose to help library developers support their clients with better deprecations. We rely on the transforming deprecations offered by Pharo and use data mining to detect the missing deprecation opportunities and generate the transformation rules. We implemented our approach for Pharo in a prototype tool called DepMiner. We have applied our tool to five open-source projects and proposed the generated deprecations to core developers of those projects. 63 recommended deprecations were accepted as pull requests.
Article
Object-sensitive pointer analysis (denoted k obj under $k$ -limiting) for an object-oriented program can be accelerated if context-sensitivity can be selectively applied to only some precision-critical variables/objects in a program. Existing pre-analyses for making such selections, which are performed as whole-program analyses to a program, are developed based on two broad approaches. One approach preserves the precision of object-sensitive pointer analysis but achieves limited speedups by reasoning about all the possible value flows in the program conservatively, while the other approach achieves greater speedups but sacrifices precision (often unduly) by examining only some but not all the value flows in the program heuristically. In this paper, we introduce a new pre-analysis approach, Turner $^{\mathcal{m}}$ (where $\mathcal {m}$ stands for modularity), that represents a sweet spot between these two existing ones, as it is designed to enable k obj to run significantly faster than the former approach and achieve significantly better precision than the latter approach. Turner $^{\mathcal{m}}$ is simple, lightweight yet effective due to two novel aspects in its design. First, we exploit a key observation that some precision-uncritical objects in the program can be approximated based on the object-containment relationship pre-established (from Andersen's analysis). In practice, this approximation introduces only a small degree of imprecision into k obj . Second, leveraging this initial approximation, we apply a novel object reachability analysis to the program by pre-analyzing its methods according to a reverse topological order of its call graph. When pre-analyzing each method, we make use of a simple DFA (Deterministic Finite Automaton) to reason about object reachability intra-procedurally from its entry to its exit along all the possible value flows established by its statements to identify its precision-critical variables/objects. In practice, this new modular object reachability analysis, which runs linearly in terms of the number of statements in the program, introduces again only a small loss of precision into k obj . We have validated Turner $^{\mathcal{m}}$ with an open-source implementation in Soot (already publicly available) against the state of the art by using a set of 12 widely used Java benchmarks and applications.
Chapter
The recent adoption of dynamic features such as Java reflection and Android dynamic code downloading (RDCL) coupled with recent security attacks that can be detected only at runtime have led to higher usage of hybrid analysis to address dependability and security concerns. While effective, however, hybrid analysis can be inefficient due to a multi-step process involving static analysis, code instrumentation, and runtime information logging. As such, existing hybrid analysis techniques can work during code development and testing, but are too slow for production and security vetting.In this paper, we introduce ReHAna, a hybrid analysis framework for Android apps. We designed our framework to perform hybrid analysis efficiently through the use of a Virtual Class-Loader (VCL), which enables incremental program analysis. We then conducted a study to assess the program analysis performance of using VCL and found that it yields several benefits over the existing compiler-based program analysis approach. We also illustrated the hybrid analysis capability of ReHAna by implementing a technique to detect and analyze dynamically loaded components based on reflection and dynamic code loading mechanisms in Android apps. We compared the performance of ReHAna against that of StaDynA, a hybrid analysis approach that performs the same task. Our empirical evaluation shows that ReHAna is as effective as StaDynA but also significantly more efficient and scalable.KeywordsProgram analysisAndroidJava reflection
Article
Traditional context-sensitive pointer analysis is hard to scale for large and complex Java programs. To address this issue, a series of selective context-sensitivity approaches have been proposed and exhibit promising results. In this work, we move one step further towards producing highly-precise pointer analyses for hard-to-analyze Java programs by presenting the Unity-Relay framework, which takes selective context sensitivity to the next level. Briefly, Unity-Relay is a one-two punch: given a set of different selective context-sensitivity approaches, say S = S1, . . . , Sn, Unity-Relay first provides a mechanism (called Unity)to combine and maximize the precision of all components of S. When Unity fails to scale, Unity-Relay offers a scheme (called Relay) to pass and accumulate the precision from one approach Si in S to the next, Si+1, leading to an analysis that is more precise than all approaches in S. As a proof-of-concept, we instantiate Unity-Relay into a tool called Baton and extensively evaluate it on a set of hard-to-analyze Java programs, using general precision metrics and popular clients. Compared with the state of the art, Baton achieves the best precision for all metrics and clients for all evaluated programs. The difference in precision is often dramatic — up to 71% of alias pairs reported by previously-best algorithms are found to be spurious and eliminated.
Article
Static checker frameworks support software developers by automatically discovering bugs that fit general-purpose bug patterns. These frameworks ship with hundreds of detectors for such patterns and allow developers to add custom detectors for their own projects. However, existing frameworks generally encode detectors in imperative specifications, with extensive details of not only what to detect but also how . These details complicate detector maintenance and evolution, and also interfere with the framework’s ability to change how detection is done, for instance, to make the detectors incremental. In this paper, we present JavaDL, a Datalog-based declarative specification language for bug pattern detection in Java code. JavaDL seamlessly supports both exhaustive and incremental evaluation from the same detector specification. This specification allows developers to describe local detector components via syntactic pattern matching , and nonlocal (e.g., interprocedural) reasoning via Datalog-style logical rules . We compare our approach against the well-established SpotBugs and Error Prone tools by re-implementing several of their detectors in JavaDL. We find that our implementations are substantially smaller and similarly effective at detecting bugs on the Defects4J benchmark suite, and run with competitive runtime performance. In our experiments, neither incremental nor exhaustive analysis can consistently outperform the other, which highlights the value of our ability to transparently switch execution modes. We argue that our approach showcases the potential of clear-box static checker frameworks that constrain the bug detector specification language to enable the framework to adapt and enhance the detectors.
Chapter
k-CFA provides the most well-known context abstraction for program analysis, especially pointer analysis, for a wide range of programming languages. However, its inherent context explosion problem has hindered its applicability. To mitigate this problem, selective context-sensitivity is promising as context-sensitivity is applied only selectively to some parts of the program. This paper introduces a new approach to selective context-sensitivity for supporting k-CFA-based pointer analysis, based on CFL-reachability. Our approach can make k-CFA-based pointer analysis run significantly faster while losing little precision, based on an evaluation using a set of 11 popular Java benchmarks and applications.
Article
Object sensitivity is widely used as a context abstraction for computing the points-to information context-sensitively for object-oriented programming languages such as Java. Due to the combinatorial explosion of contexts in large object-oriented programs, k -object-sensitive pointer analysis (under k -limiting), denoted k -obj , is often inefficient even when it is scalable for small values of k , where k ⩽ 2 holds typically. A recent popular approach for accelerating k -obj trades precision for efficiency by instructing k -obj to analyze only some methods in a program context-sensitively, determined heuristically by a pre-analysis. In this article, we investigate how to develop a fundamentally different approach, Eagle , for designing a pre-analysis that can make k -obj run significantly faster while maintaining its precision. The novelty of Eagle is to enable k -obj to analyze a method with partial context sensitivity (i.e., context-sensitively for only some of its selected variables/allocation sites) by solving a context-free-language (CFL) reachability problem based on a new CFL-reachability formulation of k -obj . By regularizing one CFL for specifying field accesses and using another CFL for specifying method calls, we have formulated Eagle as a fully context-sensitive taint analysis (without k -limiting) that is both effective (by selecting the variables/allocation sites to be analyzed by k -obj context-insensitively so as to reduce the number of context-sensitive facts inferred by k -obj in the program) and efficient (by running linearly in terms of the number of pointer assignment edges in the program). As Eagle represents the first precision-preserving pre-analysis, our evaluation focuses on demonstrating its significant performance benefits in accelerating k -obj for a set of popular Java benchmarks and applications, with call graph construction, may-fail-casting, and polymorphic call detection as three important client analyses.
Article
Java projects are often built on top of various third-party libraries. If multiple versions of a library exist on the classpath, JVM will only load one version and shadow the others, which we refer to as dependency conflicts . This would give rise to semantic conflict (SC) issues, if the library APIs referenced by a project have identical method signatures but inconsistent semantics across the loaded and shadowed versions of libraries. SC issues are difficult for developers to diagnose in practice, since understanding them typically requires domain knowledge. Although adapting the existing test generation technique for dependency conflict issues, Riddle , to detect SC issues is feasible, its effectiveness is greatly compromised. This is mainly because Riddle randomly generates test inputs, while the SC issues typically require specific arguments in the tests to be exposed. To address that, we conducted an empirical study of 316 real SC issues to understand the characteristics of such specific arguments in the test cases that can capture the SC issues. Inspired by our empirical findings, we propose an automated testing technique Sensor , which synthesizes test cases using ingredients from the project under test to trigger inconsistent behaviors of the APIs with the same signatures in conflicting library versions. Our evaluation results show that Sensor is effective and useful: it achieved a $Precision$ of 0.898 and a $Recall$ of 0.725 on open-source projects and a $Precision$ of 0.821 on industrial projects; it detected 306 semantic conflict issues in 50 projects, 70.4 percent of which had been confirmed as real bugs, and 84.2 percent of the confirmed issues have been fixed quickly.
Article
Full-text available
Since benchmarks drive computer science research and industry product development, which ones we use and how we evaluate them are key questions for the community. Despite complex runtime tradeoffs due to dynamic compilation and garbage collection required for Java programs, many evaluations still use methodologies developed for C, C++, and Fortran. SPEC, the dominant purveyor of benchmarks, compounded this problem by institutionalizing these methodologies for their Java benchmark suite. This paper recommends benchmarking selection and evaluation methodologies, and introduces the DaCapo benchmarks, a set of open source, client-side Java benchmarks. We demonstrate that the complex interactions of (1) architecture, (2) compiler, (3) virtual machine, (4) memory management, and (5) application require more extensive evaluation than C, C++, and Fortran which stress (4) much less, and do not require (3). We use and introduce new value, time-series, and statistical metrics for static and dynamic properties such as code complexity, code size, heap composition, and pointer mutations. No benchmark suite is definitive, but these metrics show that DaCapo improves over SPEC Java in a variety of ways, including more complex code, richer object behaviors, and more demanding memory system requirements. This paper takes a step towards improving methodologies for choosing and evaluating benchmarks to foster innovation in system design and implementation for Java and other managed languages.
Conference Paper
Full-text available
Reflection has always been a thorn in the side of Java static analysis tools. Without a full treatment of reflection, static analysis tools are both incomplete because some parts of the program may not be included in the application call graph, and unsound because the static analysis does not take into account reflective features of Java that allow writes to object fields and method invocations. However, accurately analyzing reflection has always been difficult, leading to most static analysis tools treating reflection in an unsound manner or just ignoring it entirely. This is unsatisfactory as many modern Java applications make significant use of reflection.
Conference Paper
Full-text available
Runtime monitoring allows programmers to validate, for in- stance, the proper use of application interfaces. Given a property specification, a runtime monitor tracks appropri- ate runtime events to detect violations and possibly execute recovery code. Although powerful, runtime monitoring in- spects only one program run at a time and so may require many program runs to find errors. Therefore, in this paper, we present ahead-of-time techniques that can (1) prove the absence of property violations on all program runs, or (2) flag locations where violations are likely to occur. Our work focuses on tracematches, an expressive runtime monitoring notation for reasoning about groups of correlated objects. We describe a novel flow-sensitive static analysis for analyz- ing monitor states. Our abstraction captures both positive information (a set of objects could be in a particular mon- itor state) and negative information (the set is known not to be in a state). The analysis resolves heap references by combining the results of three points-to and alias analyses. We also propose a machine learning phase to filter out likely false positives. We applied a set of 13 tracematches to the DaCapo benchmark suite and SciMark2. Our static analysis rules out all potential points of failure in 50% of the cases, and 75% of false positives on average. Our machine learning algorithm correctly classifies the remaining potential points of failure in all but three of 461 cases. The approach revealed defects and suspicious code in three benchmark programs.
Conference Paper
Full-text available
In an increasingly popular model of software distribution, software is developed in one computing environment and deployed in other environments by transfer over the internet. Extraction tools perform a static whole-program analysis to determine unused functionality in applications in order to reduce the time required to download applications. We have identified a number of scenarios where extraction tools require information beyond what can be inferred through static analysis: software distributions other than complete applications, the use of reflection, and situations where an application uses separately developed class libraries. This paper explores these issues, and introduces a modular specification language for expressing the information required for extraction. We implemented this language in the context of Jax, an industrial-strength application extractor for Java, and present a small case study in which different extraction scenarios are applied to a commercially available library-based application.
Conference Paper
Full-text available
Most points-to analysis research has been done on different systems by different groups, making it difficult to compare results, and to understand interactions between individual factors each group studied. Furthermore, pointsto analysis for Java has been studied much less thoroughly than for C, and the tradeoffs appear very different. We introduce Spark, a flexible framework for experimenting with points-to analyses for Java. Spark supports equality- and subset-based analyses, variations in field sensitivity, respect for declared types, variations in call graph construction, off-line simplification, and several solving algorithms. Spark is composed of building blocks on which new analyses can be based. We demonstrate Spark in a substantial study of factors affecting precision and efficiency of subset-based points-to analyses, including interactions between these factors. Our results show that Spark is not only flexible and modular, but also offers superior time/space performance when compared to other points-to analysis implementations.
Conference Paper
Full-text available
Abstract Knowing which method,parameters may be mutated during a method’s execution is useful for many,software engineering tasks. We present an approach,to discovering parameter immutability, in which several lightweight scalable analyses are combined in stages, with each stage refining the overall result. The resulting analysis is scalable and combines,the strengths of its component,analyses. As one of the component analyses, we present a novel, dynamic mutability analysis and show,how its results can be improved by random,input generation. Experimental results on programs of up to 185 kLOC demonstrate that, compared to previous approaches, our approach increases both scalability and overall accuracy.
Conference Paper
Full-text available
This article addresses the challenge of sound typestate verification, with acceptable precision, for real-world Java programs. We present a novel framework for verification of typestate properties, including several new techniques to precisely treat aliases without undue performance costs. In particular, we present a flow-sensitive, context-sensitive, integrated verifier that utilizes a parametric abstract domain combining typestate and aliasing information. To scale to real programs without compromising precision, we present a staged verification system in which faster verifiers run as early stages which reduce the workload for later, more precise, stages. We have evaluated our framework on a number of real Java programs, checking correct API usage for various Java standard libraries. The results show that our approach scales to hundreds of thousands of lines of code, and verifies correctness for 93% of the potential points of failure.
Article
Full-text available
Program slicing is a program analysis and transformation technique that has been suc- cessfully applied in a wide range of applications including program comprehension, debugging, maintenance, testing, and verication. However, there are only a few full-featured implementa- tions of program slicing that are available for industrial applications or academic research. In particular, very little tool support exists for slicing programs written in modern object-oriented languages such as Java, C#, or C++. In this paper, we present Indus 1 { a robust framework for analysis and slicing of concurrent Java programs, and Kaveri { a feature-rich Eclipse-based GUI for Indus slicing. For Indus, we describe the underlying tool architecture, analysis components, and program dependence capabilities required for slicing. In addition, we present a collection of advanced features useful for eectiv e slicing of Java programs including calling-context sensitive slicing, scoped slicing, control slicing, and chopping. For Kaveri, we discuss the design goals and basic capabilities of a graphical presentation of slicing information that is integrated into a Java development environment.
Article
Full-text available
Reducing application size is important for software that is distributed via the internet, in order to keep download times manageable, and in the domain of embedded systems, where applications are often stored in (Read-Only or Flash) memory. This paper explores extraction techniques such as the removal of unreachable methods and redundant fields, inlining of method calls, and transformation of the class hierarchy for reducing application size. We implemented a number of extraction techniques in Jax, an application extractor for Java, and evaluated their effectiveness on a set of large Java applications. We found that, on average, the class file archives for these benchmarks were reduced to 37.5% of their original size. Modeling dynamic language features such as reflection, and extracting software distributions other than complete applications requires additional user input. We present a uniform approach for supplying this input that relies on MEL, a modular specification language. We also discuss a number of issues and challenges associated with the extraction of embedded systems applications.
Article
Full-text available
This paper addresses the challenge of sound typestate verification, with acceptable precision, for real-world Java programs. We present a novel framework for verification of typestate properties, including several new techniques to precisely treat aliases without undue performance costs. In particular, we present a flowsensitive, context-sensitive, integrated verifier that utilizes a parametric abstract domain combining typestate and aliasing information.To scale to real programs without compromising precision, we present a staged verification system in which faster verifiers run as early stages which reduce the workload for later, more precise, stages.We have evaluated our framework on a number of real Java programs, checking correct API usage for various Java standard libraries. The results show that our approach scales to hundreds of thousands of lines of code, and verifies correctness for 93% of the potential points of failure.
Article
Full-text available
Informally, a call graph represents calls between entities in a given program. The call graphs that compilers compute to determine the applicability of an optimization must typically be conservative: a call may be omitted only if it can never occur in any execution of the program. Numerous software engineering tools also extract call graphs with the expectation that they will help software engineers increase their understanding of a program. The requirements placed on software engineering tools that compute call graphs are typically more relaxed than for compilers. For example, some false negatives—calls that can in fact take place in some execution of the program, but which are omitted from the call graph—may be acceptable, depending on the understanding task at hand. In this article, we empirically show a consequence of this spectrum of requirements by comparing the C call graphs extracted from three software systems (mapmaker, mosaic, and gcc) by nine tools (cflow, cawk, CIA, Field, GCT, Imagix, LSME, Mawk, and Rigiparse). A quantitative analysis of the call graphs extracted for each system shows considerable variation, a result that is counterintuitive to many experienced software engineers. A qualitative analysis of these results reveals a number of reasons for this variation: differing treatments of macros, function pointers, input formats, etc. The fundamental problem is not that variances among the graphs extracted by different tools exist, but that software engineers have little sense of the dimensions of approximation in any particular call graph. In this article, we describe and discuss the study, sketch a design space for static call graph extractors, and discuss the impact of our study on practitioners, tool developers, and researchers. Although this article considers only one kind of information, call graphs, many of the observations also apply to static extractors of other kinds of information, such as inheritance structures, file dependences, and references to global variables.
Article
Full-text available
Jalapeño is a virtual machine for Java™ servers written in the Java language. To be able to address the requirements of servers (performance and scalability in particular), Jalapeño was designed “from scratch“ to be as self-sufficient as possible. Jalapeño's unique object model and memory layout allows a hardware null-pointer check as well as fast access to array elements, fields, and methods. Run-time services conventionally provided in native code are implemented primarily in Java. Java threads are multiplexed by virtual processors (implemented as operating system threads). A family of concurrent object allocators and parallel type-accurate garbage collectors is supported. Jalapeño's interoperable compilers enable quasi-preemptive thread switching and precise location of object references. Jalapeño's dynamic optimizing compiler is designed to obtain high quality code for methods that are observed to be frequently executed or computationally intensive.
Article
Full-text available
The authors introduce a new programming language concept, called typestate, which is a refinement of the concept of type. Whereas the type of a data object determines the set of operations over permitted on the object, typestate determines the subset of these operations which is permitted in a particular context. Typestate tracking is a program analysis technique which enhances program reliability by detecting at compile-time syntactically legal but semantically undefined execution sequences. These include reading a variable before it has been initialized and dereferencing a pointer after the dynamic object has been deallocated. The authors define typestate, give examples of its application, and show how typestate checking may be embedded into a compiler. They discuss the consequences of typestate checking for software reliability and software structure, and summarize their experience in using a high-level language incorporating typestate checking.
Conference Paper
Full-text available
Informally, a call graph represents calls between entities in a given program. The call graphs that compilers compute to determine the applicability of an optimization must typically be conservative: a call may be omitted only if it can never occur an any execution of the program. Numerous software engineering tools also extract call graphs, with the expectation that they will help software engineers increase their understanding of a program. The requirements placed on software engineering tools when computing call graphs are typically more related than for compilers. For example, some false negatives-calls that can in fact take place in some execution of the program, but which are omitted from the call graph-may be acceptable, depending on the understanding task at hand. In this paper we empirically show a consequence of this spectrum of requirements by comparing the C call graphs extracted from three software systems (mapmaker, mosaic, and gee) by five extraction tools (cflow, CIA, Field, mk-functmap, and rigiparse). A quantitative analysis of the call graphs extracted for each system shows considerable variation, a result that is counterintuitive to many experienced software engineers. A qualitative analysis of these results reveals a number of reasons for this variation: differing treatments of macros, function pointers, input formats, etc. We describe and discuss the study, sketch the design space, and discuss the impact of our study on practitioners, tool developers, and researchers
Article
Full-text available
This paper presents Soot, a framework for optimizing Java bytecode. The framework is implemented in Java and supports three intermediate representations for representing Java bytecode: Baf, a streamlined representation of bytecode which is simple to manipulate; Jimple, a typed 3-address intermediate representation suitable for optimization; and Grimp, an aggregated version of Jimple suitable for decompilation. We describe the motivation for each representation, and the salient points in translating from one representation to another. In order to demonstrate the usefulness of the framework, we have implemented intraprocedural and whole program optimizations. To show that whole program bytecode optimization can give performance improvements, we provide experimental results for 12 large benchmarks, including 8 SPECjvm98 benchmarks running on JDK 1.2 for GNU/Linuxtm . These results show up to 8% improvement when the optimized bytecode is run using the interpreter and up to 21% when run...
Conference Paper
Since benchmarks drive computer science research and industry product development, which ones we use and how we evaluate them are key questions for the community. Despite complex runtime tradeoffs due to dynamic compilation and garbage collection required for Java programs, many evaluations still use methodologies developed for C, C++, and Fortran. SPEC, the dominant purveyor of benchmarks, compounded this problem by institutionalizing these methodologies for their Java benchmark suite. This paper recommends benchmarking selection and evaluation methodologies, and introduces the DaCapo benchmarks, a set of open source, client-side Java benchmarks. We demonstrate that the complex interactions of (1) architecture, (2) compiler, (3) virtual machine, (4) memory management, and (5) application require more extensive evaluation than C, C++, and Fortran which stress (4) much less, and do not require (3). We use and introduce new value, time-series, and statistical metrics for static and dynamic properties such as code complexity, code size, heap composition, and pointer mutations. No benchmark suite is definitive, but these metrics show that DaCapo improves over SPEC Java in a variety of ways, including more complex code, richer object behaviors, and more demanding memory system requirements. This paper takes a step towards improving methodologies for choosing and evaluating benchmarks to foster innovation in system design and implementation for Java and other managed languages.
Article
We present an efficient algorithm for computing the procedure call graph, the program representation underlying most interprocedural optimization techniques. The algorithm computes the possible bindings of procedure variables in languages where such variables only receive their values through parameter passing, such as Fortran. We extend the algorithm to accommodate a limited form of assignments to procedure variables. The resulting algorithm can also be used in analysis of functional programs that have been converted to Continuation-Passing-Style. We discuss the algorithm in relationship to other call graph analysis approaches. Many less efficient techniques produce essentially the same call graph. A few algorithms are more precise, but they may be prohibitively expensive depending on language features.
Article
This paper extends static typestate analysis to temporal specifications of groups of interacting objects, which are expressed using tracematches. Unlike typestate, a tracematch state may change due to operations on any of a set of objects bound by the tracematch. The paper proposes a lattice-based operational semantics equivalent to the original tracematch semantics but better suited to static analysis. The paper defines a static analysis that computes precise local points-to sets and tracks the flow of individual objects, thereby enabling strong state updates of the tracematch state. The analysis has been proved sound with respect to the semantics. A context-sensitive version of the analysis has been implemented as instances of the IFDS and IDE algorithms. The analysis was evaluated on tracematches used in earlier work and found to be very precise. Remaining imprecisions could be eliminated with more precise modeling of references from the heap and of exceptional control flow.
Conference Paper
Typestate analysis determines whether a program violates a set of finite-state properties. Because the typestate-analysis problem is statically undecidable, researchers have proposed a hybrid approach that uses residual monitors to signal prop- erty violations at runtime. We present an efficient novel static typestate analysis that is flow-sensitive, partially context-sensitive, and that gen- erates residual runtime monitors. To gain efficiency, our analysis uses precise, flow-sensitive information on an intra- procedural level only, and models the remainder of the pro- gram using a flow-insensitive pointer abstraction. Unlike previous flow-sensitive analyses, our analysis uses an addi- tional backward analysis to partition states into equivalence classes. Code locations that transition between equivalent states are irrelevant and require no monitoring. As we show in this work, this notion of equivalent states is crucial to obtaining sound runtime monitors. We proved our analysis correct, implemented the analysis in the Clara framework for typestate analysis, and applied it to the DaCapo benchmark suite. In half of the cases, our analysis determined exactly the property-violating pro- gram points. In many other cases, the analysis reduced the number of instrumentation points by large amounts, yielding significant speed-ups during runtime monitoring.
Conference Paper
Many compiler optimizations and software engineering tools need precise pointer analyses to be eective. Unfortunately, many Java features, such as dynamic class loading, reflec- tion, and native methods, make pointer analyses dicult to develop. Hence, prior pointer analyses for Java either ignore those features or are overly conservative. We describe and evaluate a pointer analysis that deals with all Java language features. Our analysis is based on Andersen's inclusion-constraint based pointer analysis. For statically-linked languages, An- dersen's analysis finds constraints based on a static whole- program analysis of the code, and then propagates the con- straints to obtain points-to information. Our version of Andersen's analysis handles features such as dynamic class loading by generating constraints at runtime and propagat- ing the constraints whenever a client of the analysis needs points-to information. We evaluate the correctness of our analysis by comparing its results with pointers created at runtime. We evaluate its performance by running it on a number of Java programs and measuring metrics such as propagation time.
Conference Paper
We perform static analysis of Java programs to answer a simple question: which values may occur as results of string expressions? The answers are summarized for each expression by a regular language that is guaranteed to contain all possible values. We present several applications of this analysis, including statically checking the syntax of dynamically generated expressions, such as SQL queries. Our analysis constructs flow graphs from class files and generates a context-free grammar with a nonterminal for each string expression. The language of this grammar is then widened into a regular language through a variant of an algorithm previously used for speech recognition. The collection of resulting regular languages is compactly represented as a special kind of multi-level automaton from which individual answers may be extracted.
Conference Paper
This paper presents a static analysis of typestate-like temporal specifications of groups of interacting objects, which are expressed using tracematches. Whereas typestate expresses a temporal specification of one object, a tracematch state may change due to operations on any of a set of related objects bound by the tracematch. The paper proposes a lattice-based operational semantics equivalent to the original tracematch semantics but better suited to static analysis. The paper defines a static analysis that computes precise local points-to sets and tracks the flow of individual objects, thereby enabling strong updates of the tracematch state. The analysis has been proved sound with respect to the semantics. A context-sensitive version of the analysis has been implemented as instances of the IFDS and IDE algorithms. The analysis was evaluated on tracematches used in earlier work and found to be very precise. Remaining imprecisions could be eliminated with more precise modeling of references from the heap and of exceptional control flow.
Conference Paper
Many popular scripting languages such as Ruby, Python, and Perl include highly dynamic language constructs, such as an eval method that evaluates a string as program text. While these constructs allow terse and expressive code, they have traditionally obstructed static analysis. In this paper we present PRuby, an extension to Diamondback Ruby (DRuby), a static type inference system for Ruby. PRuby augments DRuby with a novel dynamic analysis and transformation that allows us to precisely type uses of highly dynamic constructs. PRuby's analysis proceeds in three steps. First, we use run-time instrumentation to gather per-application profiles of dynamic feature usage. Next, we replace dynamic features with statically analyzable alternatives based on the profile. We also add instrumentation to safely handle cases when subsequent runs do not match the profile. Finally, we run DRuby's static type inference on the transformed code to enforce type safety. We used PRuby to gather profiles for a benchmark suite of sample Ruby programs. We found that dynamic features are pervasive throughout the benchmarks and the libraries they include, but that most uses of these features are highly constrained and hence can be effectively profiled. Using the profiles to guide type inference, we found that DRuby can generally statically type our benchmarks modulo some refactoring, and we discovered several previously unknown type errors. These results suggest that profiling and transformation is a lightweight but highly effective approach to bring static typing to highly dynamic languages.
Conference Paper
Calling context enhances program understanding and dynamic analyses by providing a rich representation of program location. Compared to imperative programs, object-oriented programs use more interprocedural and less intraprocedural control flow, increasing the importance of context sensitivity for analysis. However, prior online methods for computing calling context, such as stack-walking or maintaining the current location in a calling context tree, are expensive in time and space. This paper introduces a new online approach called probabilistic calling context (PCC) that continuously maintains a probabilistically unique value representing the current calling context. For millions of unique contexts, a 32-bit PCC value has few conflicts. Computing the PCC value adds 3% average overhead to a Java virtual machine. PCC is well-suited to clients that detect new or anomalous behavior since PCC values from training and production runs can be compared easily to detect new context-sensitive behavior; clients that query the PCC value at every system call, Java utility call, and Java API call add 0-9% overhead on average. PCC adds space overhead proportional to the distinct contexts stored by the client (one word per context). Our results indicate PCC is efficient and accurate enough to use in deployed software for residual testing, bug detection, and intrusion detection.
Conference Paper
Comparing program analysis results from different static and dy- namic analysis tools is difficult and therefore too rare, esp ecially when it comes to qualitative comparison. Analysis results can be strongly affected by specific details of programs being anal yzed, so quantitative evaluation should be supplemented by qualitative identification of those details. Our general aim is to develo p tools to reduce the difficulty of qualitative comparison. In this p aper, we focus on comparison of call graphs in particular. We present two complementary tools for comparing call graphs. Our main contribution is a call graph difference search tool that ranks call graph edges by their likelihood of causing large differ- ences in the call graphs. This is complemented by a simple interac- tive call graph viewer that highlights specific differences between call graphs, and allows a user to browse through them. In a search for the causes of call graph differences, a user first uses the search tool to identify which of the thousands of spurious edges to look at more closely, and then uses the interactive viewer to determine in detail the root cause of a difference. We present the ranking algorithm used in the difference search tool. We also report on a case study using the comparison tools to determine the most important sources of imprecision in a typical static call graph by comparing it to a dynamic call graph of the same benchmark.
Conference Paper
Reflection plays a major role in the programming of generic applications. However, it introduces an interpretation layer which is detrimental to performance. A solution consists of relying on partial evaluation to remove this interpretation layer. This paper deals with improving a standard partial evaluator in order to handle the Java reflection API. The improvements basically consist of taking type information into account when distinguishing between static and dynamic data, as well as introducing two new specialization actions: reflection actions. Benchmarks using the serialization framework show the benefits of the approach.
Conference Paper
Programmers using complex libraries and frameworks are faced with the difficult task of ensuring that their implementations comply with complex and informally described rules for proper sequencing of API calls. Recent advances in static and dynamic techniques for checking explicit specifications of program typestate properties have shown promise in addressing this challenge. Unfortunately, static typestate analyses are limited in their scalability and dynamic analyses can suffer from significant run-time overhead. In this paper, we present an approach that exploits information calculated by flow-sensitive static typestate analyses to reformulate the original analysis problem as a residual dynamic typestate analysis. We demonstrate that residual analyses retain the error reporting of unoptimized dynamic analysis while offering the potential for significantly reducing analysis cost
Conference Paper
This paper defines a new analysis paradigm, blended program anal- ysis, that enables practical, effective analysis of large framework- based Java applications for performance understanding. Blended analysis combines a dynamic representation of the program calling structure, with a static analysis applied to a region of that calling structure with observed performance problems. A blended escape analysis is presented which enables approximation of object effec- tive lifetimes, to facilitate explanation of the usage of newly created objects in a program region. Performance bottlenecks stemming from overuse of temporary structures are common in framework- based applications. Metrics are introduced to expose how, in ag- gregate, these applications make use of new objects. Results of empirical experiments with the Trade benchmark are presented. A case study demonstrates how results from a blended escape analysis can help locate, in a region which calls 223 distinct methods, the single call path responsible for a performance problem involving objects created at 9 distinct sites and as far as 6 call levels away.
Article
How Coverity built a bug-finding tool, and a business, around the unlimited supply of bugs in software systems.
Article
Pointer analysis benefits many useful clients, such as compiler optimizations and bug finding tools. Unfortunately, common programming language features such as dynamic loading, reflection, and foreign language interfaces, make pointer analysis difficult. This article describes how to deal with these features by performing pointer analysis online during program execution. For example, dynamic loading may load code that is not available for analysis before the program starts. Only an online analysis can analyze such code, and thus support clients that optimize or find bugs in it. This article identifies all problems in performing Andersen's pointer analysis for the full Java language, presents solutions to these problems, and uses a full implementation of the solutions in a Java virtual machine for validation and performance evaluation. Our analysis is fast: On average over our benchmark suite, if the analysis recomputes points-to results upon each program change, most analysis pauses take under 0.1 seconds, and add up to 64.5 seconds.
Article
The authors introduce a new programming language concept, called typestate, which is a refinement of the concept of type. Whereas the type of a data object determines the set of operations ever permitted on the object, typestate determines the subset of these operations which is permitted in a particular context. Typestate tracking is a program analysis technique which enhances program reliability by detecting at compile-time syntactically legal but semantically undefined execution sequences. These include reading a variable before it has been initialized and dereferencing a pointer after the dynamic object has been deallocated. The authors define typestate, give examples of its application, and show how typestate checking may be embedded into a compiler. They discuss the consequences of typestate checking for software reliability and software structure, and summarize their experience in using a high-level language incorporating typestate checking.
Article
We present an iterative technique in which model checking and static analysis are combined to verify large software systems. The role of the static analysis is to compute partial order information which the model checker uses to reduce the state space. During exploration, the model checker also computes aliasing information that it gives to the static analyzer which can then refine its analysis. The result of this refined analysis is then fed back to the model checker which updates its partial order reduction. At each step of this iterative process, the static analysis computes optimistic information which results in an unsafe reduction of the state space. However, we show that the process converges to a fixed point at which time the partial order information is safe and the whole state space is explored.
Article
interpretation, alias analysis, dataflow analysis, destructive updating, pointer analysis, shape analysis, shape graphs, static analysis 1. INTRODUCTION This article concerns the static analysis of programs that perform destructive updating on heap-allocated storage. It addresses problems that can be looked at--- depending on one's point of view---as pointer analysis problems, alias analysis problems, sharing-analysis problems, storage analysis problems (also known as shape analysis problems), or typechecking problems. The information obtained is useful, for instance, for generating e#cient sequential or parallel code. Throughout most of the article, we emphasize the application of our work to shape-analysis problems. The goal of shape analysis is to give, for each program point, a conservative, finite characterization of the possible "shapes" that the program 's heap-allocated data structures can have at that point. We illustrate our approach by means of a running example in which w...
Taming Reflection (Extended version)
  • Eric Bodden
  • Andreas Sewe
  • Jan Sinschek
Eric Bodden, Andreas Sewe, Jan Sinschek, and Mira Mezini. Taming Reflection (Extended version). Technical Report TUD-CS-2010-0066, CASED, March 2010. http://cased.de/.
Amer Diwan, and Michael Hind. Fast online pointer analysis
  • Martin Hirzel
  • Daniel Von Dincklage
Martin Hirzel, Daniel Von Dincklage, Amer Diwan, and Michael Hind. Fast online pointer analysis. TOPLAS, 29(2):11, 2007.
FIPS PUB 180--3. National Institute of Standards and Technology, Information Technology Laboratory
  • National Institute of Standards and Technology