Detecting Unauthorised Information Flows Using Points-To Analysis
This article describes how standard static program analysis techniques for object-oriented programming languages can be used to detect potential information flow violations in object-oriented programs. We focus on points-to analysis and show how the security properties of confidentiality and integrity can be expressed using the points-to information. This article reviews the literature related to points-to analysis and program-level information flow security and describes the key steps necessary to conduct a security analysis using points-to information. The authors also outline the challenges and solutions to scale these analyses to large code-bases like the Java Development Kit [JDK (Java and JDK are registered trademarks of Oracle and/or its affiliates. Other names may be trademarks of their respective owners)].
Padmanabhan Krishnan, Oracle Labs
Yi Lu, Oracle Labs
Kagalavadi Ramesh Raghavendra, Oracle Labs
Languages like Java [ 1 ] allow the execution of untrusted code (e.g. code that comes from an unverified and hence potentially malicious source) along with the execution of trusted code. To ensure security, the language provides primitives for fine-grained access control and uses stack inspection [ 2 , 3 ] as the mechanism to enforce access control during runtime. The developer can use these primitives to ensure that the execution of untrusted code does not violate any intended security properties. However, the stack-based enforcement mechanism provided by Java is not sufficient to ensure security, especially in the context of information flow.
Information flow in a given program is how information propagates (either by explicit copying or when information influences the control flow) from one program point to another during its execution. Access control for security is a means to prevent information from reaching certain parts of the program. Higher privileges are required to access sensitive information and these privileges need to be granted by a trusted entity. If an entity does not have the privileges to access sensitive information, the access control mechanism will deny the access and perhaps flag an exception. Sabelfeld and Myers [ 4 ] show that, in general, access control alone is not sufficient to ensure information flow security as it does not take into account what information is shared. The Java model relies on the developer having implemented the necessary access control to guarantee that incorrect information flows are prohibited. This requires the developer inserting suitable permission checks in the code that raise a security exception if the information flow requirement is violated. It is known that linking information flow to the control flow of the program is difficult which results in programmer introduced security defects. This is mainly due to data flowing into non-local parts of the code. In order to detect such defects tracking information flow in the presence of access control constructs is important.
This article summarises existing work in the area of program analysis and shows how they can be applied in the context of information flow security. It does not cover all aspects of information flow; the reader is referred to the article by Hedin and Sabelfeld [ 5 ] for a more comprehensive tutorial that is focused on information flow control. Our aim is to show how static program analysis techniques in general and points-to analysis specifically can be used to detect potential information flow violations in object-oriented programs. We show how these apply to the Java Secure Coding Guidelines [ 6 ], using the results of a points-to analysis. While a description of the vulnerabilities that we can detect is beyond the scope of this article, we present one concrete example from the OpenJDK7-b147 to illustrate applicability.
The structure of the article is as follows: the section Points-To Analysis summarises the state of the art in the abstractions suitable for object-oriented programs; the section Security Concepts introduces the key definitions relevant to information flow and access control; and the section Information Flow Analysis for Java shows how the points-to analysis can be used to implement information flow analysis with a focus on detecting potential security defects in Java code including the JDK platform. These concepts are explained using small simple snippets of code fragments that illustrate the key ideas that underpin these techniques.
Static program analysis [ 7 , 8, 9 ] is one technique to detect security violations. Points-to analysis is a fundamental static analysis technique that is the basis for numerous other analyses [ 10, 11, 12 ], especially for object-oriented languages like Java. Points-to analysis computes all the data (or objects) a pointer variable (or a reference in Java) and fields in objects can point to while executing a program. If a static points-to analysis has to terminate, the data (or their abstraction) that a variable can point to, which are objects in Java, need to be finite. Thus concrete runtime objects are abstracted to approximations (also called heap abstractions) that are finite. The precision and scalability of the points-to analysis depends on the chosen abstractions [ 13 , 14 ].
The basic abstraction we consider is one where all objects created by a specific new statement are approximated by a single object. This is referred to as the object creation site abstraction. So the location of the statement (e.g. line number) represents all concrete objects created by the statement at runtime. Another aspect of the abstraction is related to fields. For example, if an object has two fields f1 and f2 they could point to different objects. We need to represent the abstract objects pointed to by fields of abstract objects.
Consider the simple example shown in Fig. 1. The concrete and abstract behaviour after two iterations of the program is shown in Fig. 2. In the concrete execution two objects o 1 and o 2 are created. The variables x and head point to the last created object. The next field of o 2 points to o 1 while the next field of o 1 points to null . The abstract behaviour keeps track of only the object creation sites (in this case location a at line 3). The variable x always points to the location while a head could point to either null or a. Updating the field via x. next= head implies that a’s field points to itself or to null .
a Concrete information
b Abstract information
Formally, there are two types of edges in the points-to graph. The first type is between variables and the abstracted objects indicated by a dotted line and the second type is between objects which is indicated by a dashed line in Fig. 2.
Our implementation uses Datalog [ 15 ] to express the analysis using relations that are derived from those in the DOOP framework [ 12 ]. Datalog is a programming language based on logic (hence declarative in nature), but also supports relational queries with recursion. DOOP is a framework where the analysis for object-oriented programs is expressed in Datalog. Full details including specifications that can be downloaded is available at http://doop.program-analysis.org/index.html.
We use natural language instead of Datalog to explain the specifications that are relevant for our analyses. We assume that the sets Variables (for program variables), Objects (for object creation sites), Fields (for fields), Methods (for methods), Invocations (for invocations) are defined using the syntactic structure of the program that is being analysed. The points-to information is represented by the relations VarPointsTo( v, o) where v is the variable and o the object it points to, and FieldPointsTo( b, f, o) where b represents the base object, f the field in the base object and o the object that the field points to. Formally, VarPointsTo ⊆ Variables × Objectsand FieldPointsTo ⊆ Objects × Fields × Objects.
The points-to information is also used to resolve virtual calls. For example, consider the code fragment shown in Fig. 3 where classC defines method m and has two subclasses, say C1 and C2, both of which override m. The invocation o.m() depends on the type of the object pointed to by the variable o. The invocation is resolved to the method(s) in the class(es) of the object(s) it points-to. The exact method called depends on the resulting of evaluating e; but statically this may not be known. Thus one has to conclude that o ay point-to an object of type C1 or of type C1 and thus o.m() could resolve to m in either C1 or C2. In general, the potential targets of a virtual call is represented by the relation CallGraph( invocation, method), where the virtual call invocation can potentially be resolved to method. See [ 13 , 16 ] for a more detailed discussion of the various choices available and their implications. In summary, the points-to analysis describes the potential values in terms of objects a variable could have and the state of the heap in terms of which objects a field of an object could contain.
Subclassing and virtual calls
We now describe two specific analyses, namely escape and taint, that are relevant to our discussion of information flow security. We express these analyses using the points-to information and relations that encode the structure and syntactic elements of the program.
Escape analysis is used traditionally in compilers to determine which objects are local to a method and hence can be allocated on the stack. In Java programs, an object escapes a method if it is explicitly returned by the method or if it is stored in a field of an object that also escapes [ 17 ]. The standard escape analysis can be adapted to detect potential security violations. Objects that are created by security-sensitive operations, typically in a privileged context, must not escape to an untrusted entity. Two rules which describe when an object escapes from the library to the application are now presented:
- Any object pointed to by the return variable of a public API method escapes. This is expressed formally in Fig. 4.
- The rule describing the case where any object pointed to by a readable field of an escaped object escapes is shown in Fig. 5
Escape via return
Field of escaped object
Here the relation PublicEntry identifies the public APIs and the relation ReturnVariableMethod identifies the return variable(s) of a given method.
An example of a value escaping is shown on Lines 9 and 13 in Fig. 7. Although the value generated by the call to generateVal is stored in a private field, the public method getVal can be used to return this value to the environment.
Taint analysis in a security context determines whether the values from untrusted (i.e., potentially tainted) sources reach a secure location. This can be viewed as a source to sink dataflow problem where the source is the untrusted entity and the sink is the secure location. This can be expressed using the points-to information. If the source variable of the taint points to a particular object, and if the sink variable also points to the same object, one can conclude that there is flow of a tainted value from the source to the sink.
The rule in Fig. 6specifies that any parameter of the main method in an application (or a public API method in a library) is a source of taint. Here we assume that the relation External identifies objects that come from outside the program/library and hence are tainted.
Public entry: source of taint
The source of the taint and its associated sink is shown on Lines 5 and 8 in Fig. 7. The value in the field privField is tainted as the public method store can be used to store the value supplied by the environment into privField. This implies that the invocation of min the method entry can actually result in a call to any method defined in class T or any suitable subclass.
The second case is when any publicly writeable field of a publicly accessible object is a source of taint. Hence, if an object escapes, its publicly writeable field can point-to a tainted object. So the rule for identifying tainted values needs to be related to the escape analysis.
This is also shown in Fig. 7 As the value in field escapes via a call to getVal, the value in field. next can be tainted. This can occur via the use of the public method F.set to set the value of field. next. The result of such a taint implies that the invocation field. next.helper in the method anotherEntry can be to any suitable method in either the class F or any of its subclasses. Thus the source of the taint of an escaped value on Line 24 can reach the sink on Line 18.
Escape and taint
The general rules specifying such an interaction is shown in Fig. 8.
Escaped object source of taint
Thus far we have expressed escape and taint analysis using points-to information. The concept of escape and taint is not specific to security. In the next section we show how the security concepts of confidentiality and integrity can be expressed using our escape and taint analysis. This enables us to derive a security specific analysis from a general analysis.
There are numerous concepts that are related to programming language-based security and information flow [ 4 ]. The two main information flow security concepts we consider are confidentiality with declassification and integrity with sanitisation. We consider issues that arise from only explicit flows and not implicit flows [ 5 ].
Confidentiality is the requirement that sensitive information that has a particular set of privileges should not flow to entities having fewer privileges. For example, if the permissions p and q are associated with the value v, confidentiality demands that v is not accessible by entities that do not have both p and q. This can be expressed using the escape analysis outlined earlier. The only extension required is the association of the set of privileges with the various entities. As this is language-pecific, we will discuss the specific analysis for Java later.
To handle cases where information needs to be released to non-privileged entities in a safe manner, any confidential information must be suitably declassified. Declassification is the process of taking a value whose access requires certain privileges and altering it to another value that can be released to entities that do not have the privileges.
To support declassification in a static program analysis, knowledge of constructs that result in declassified values is necessary. For the purposes of illustration we assume that the set of declassification methods are identified.
The program fragment in Fig. 9 illustrates the release of declassified information. The value returned by the method generateValueis classified and hence the object pointed to by the variable confid should not escape. If the method modify is not marked as a declassifier, the value pointed to by the variable stillConfid is also confidential as it depends on a the parameter passed to modifywhich is a confidential value. If the method declassify is marked as a declassifier, the value pointed to by the variable declassified is safe to be released even though the input parameter to declassified is confidential. The value in finalValue can also be released as it depends on a value that is already declassified. Thus the escape of the object pointed to by finalValue is safe.
A confidentiality requirement is violated if an object that depends on a security-sensitive value or is created by a security-sensitive method escapes without passing through a declassifier. Towards specifying this we assume that the relation IsSecuritySensitiveidentifies objects that are security sensitive and the relation IsSecuritySensitiveMethod identifies methods that are the source of the security sensitive objects. The rule that detects confidentiality violations and its auxiliary rules (for defining declassification represented by the relation Declassification and security sensitive values represented by the relation IsSecuritySensitive) are given in Fig. 10
Violation of confidentiality
Integrity is the requirement that information from an entity that does not have a certain privilege does not flow to an entity that has the privilege. Hence information from untrusted sources must not flow to any computation that could generate sensitive information as we cannot be sure if the data constructed by the untrusted source satisfies the desired properties. For instance, if a value v is generated by an untrusted entity and method m computes a security-sensitive value then the execution of m must not use any value that is dependent on v. Like confidentiality, a blanket integrity requirement is often too strong. Sometimes it is necessary to accept input that satisfies certain properties from untrusted sources to perform a security-sensitive operation. If the input value is sanitised, one can then be sure that it satisfies the required property and can be used safely. Sanitisation is the process of converting untrusted information to trusted information in order to enable its use in a security-sensitive environment.
The program fragment in Fig. 11illustrates integrity and sanitisation. As the environment can supply the value to useValue the object pointed to by param needs to be considered to be tainted. If the method modify is not a sanitiser, the value in the variablestillTainted is also tainted as it depends on the value in param. However the value in safeValue will be deemed to be sanitised if the method sanitise is marked as a sanitiser. Thus the value pointed to by the field safeValue is sanitised and can be viewed as having integrity.
Integrity at a location is guaranteed if all information that emanates from a tainted source are sanitised before they reach the location. The specification to identify integrity violations and the auxiliary definition to identify values that are sanitised is given in Fig. 12
Violation of integrity
In the next section we apply the concepts developed earlier to the specific case of Java.
In this section we summarise some of the key security concepts in Java and guidelines to write secure Java code. We then describe the challenges in applying our points-to based framework to detect potential security violations and conclude with a concrete example to illustrate the usefulness of our analysis.
Java security model
Here a brief overview of Java security model is presented. Please refer the book [ 18 ] for full details of the Java security architecture. Java applications may be run in two modes – fully privileged mode and secure mode. In fully privileged mode there is no security manager and the JDK gives full access to the application.
In the secure mode, the host-controlled policy file assigns different permissions to different Java applications. The Java applications are then run in the presence of security manager. The JDK performs security checks using this security manager by invokingcheckPermission(perm) where perm is the permission guarding a security sensitive operation inside JDK. If all the methods on the current call stack have the permission perm then the call returns normally, otherwise a security exception is thrown. Note that JDK always has all permissions and the permissions possessed by applications are governed by the policy file.
To allow the JDK to execute some code on behalf of the user JDK uses the doPrivileged methods. The doPrivileged(action, acc)statement runs the code inside action object with the privileges of AccessControlContext acc instead of the current call stack. When acc is null, it amounts to running the code inside action object in a fully privileged mode.
Class loaders form another aspect to the Java Security Model. As the name suggests they load classes upon a request from JVM. A complete description of class loaders is beyond the scope of this article. An interested reader is referred to [ 18 ] for a deeper understanding. For this article, we are interested in methods which vary their behaviour according to immediate caller's class. They are considered caller-sensitive methods or CSMs [ 19 ]. For example, the caller-sensitive methodjava.io.ObjectStreamField.getType bypasses the security manager checks depending on the immediate caller's class loader.
Information flow in Java secure coding guidelines
The Java Secure Coding Guidelines [ 6 ] provide recommendations for JDK developers to ensure that the code they write is secure. Section 9 of the guidelines describes potential access control vulnerabilities inside the JDK. These guidelines typically restrict information flows between unauthorised applications and security-sensitive operations and data. These undesired information flows may be detected using taint and escape analysis as described in the previous section. In these coding guidelines the notion of security-sensitive operations are approximated to caller-sensitive methods and doPrivileged methods.
An unauthorised flow of information could be sanitised or declassified because of an appropriate checkPermission invocation. Consider an invocation of a caller-sensitive method of the form v=csm(args). If any of the arguments from args is tainted, every path from the public API to the invocation must have an appropriate checkPermission. Similarly, if the object pointed to by v escapes, every path from the invocation back to the public API must have appropriate checkPermission. This can be checked by following the control flow graph.
Similar to caller-sensitive methods, Section 9.3 of the guideline suggests that any invocation of the methodAccessController.doPrivileged(action, acc) with tainted values is a potential vulnerability. This means that the action argument should not contain code operating on tainted data.
Both the cases of CSM and doPrivileged are unified by a general specification which takes as parameter the taint source, and the destination of interest. Any check permission call on the path is deemed to sanitise the tainted input. Testing if all paths have a permission check can be expressed using the classical gen/kill dataflow analysis [ 20 ]. Every taint source generates tainted information while an invocation to a suitable check permission kills the taint (i.e. sanitised). An existence of a path from the source to the destination that is not killed is a violation.
A pictorial representation is shown in Fig. 13 and the logical encoding is shown in Fig. 14. In Fig. 13 there are two paths (from pe1 and pe 2) to the doPrivileged call which can result in potential invocations to methods m 1 and m 2. The value in variable y is sanitised by the permission check and hence the call to m 2 is safe. However, as x is not sanitised and used by m 1 in a privileged context, the doPrivileged invocation violates the security guideline. So the existence of a single unsanitised path is sufficient to flag a violation. This requirement is expressed in Fig. 14 The relation TaintSource identifies the public entry methods as the source of the taint. The relevant destination nodes are either those that are caller-sensitive methods or those that can be reached via adoPrivileged call. Here the relation DoPrivCSM identifies the basic-blocks that have invocations to either call-sensitive methods or call to doPrivileged and the relation Reachable is defined using the relation CallGraph and the location of the invocations in methods. The relations StartNode and EdgeBB are defined on the basic blocks of the relevant program elements. The relationUnsanitised identifies nodes (or statements) that are not sanitised. Clearly, the source node is not sanitised (i.e. has tainted information). Moreover, if a node has tainted information then its successor which is not a check permission invocation also receives tainted information.
Violation due to the flow of unsanitised tainted data to doPrivileged
Rules defining violation involving tainted values
Fig. 15 has a pictorial depiction of four of the cases that defines sanitisation. The top-ost case indicates that if the incoming edge is not sanitised, and there is no check permission in the basic block, the outgoing edge is also not sanitised. The next case indicates that if there is a check permission in the basic block, the outgoing edge is sanitised. The last two cases are a generalisation of the other two flows and consider inter-procedural paths have/do not have a check permission.
Cases of sanitisation
Section 9.5 of the guidelines recommends that the values created in a privileged context are not returned to untrusted code. This is a direct application of the escape analysis. Although the guideline itself does not describe declassification, the document dealing with system-level properties https://docs.oracle.com/javase/tutorial/deployment/doingMoreWithRIA/properties.html describes how the values that are generated using system privileges can be returned safely to untrusted code. The rules to detect potential violations should not report the escape of such values. The rules to handle this are similar to the specifications given in Fig. 14, but uses the relation ConfidentialityViolation developed for the escape analysis.
Challenges for JDK
We now outline two key challenges when applying the above technique to systems like the JDK.
First is that the JDK is a library and can be used by any application. Hence the analysis has to account for all possible applications. We analyse libraries by using types to approximate the object creation sites of the unknown programs [ 21 ]. Thus our abstraction uses real object creation sites for the elements from the JDK and types which are proxy for the object creation sites for the elements that are part of the program. This is related to the definition of the relation TaintSource.
The second challenge is the size of the program. For instance, OpenJDK7 build 147 has more than 1.0 million variables and 300,000 object creation sites. The context-insensitive points-to set has more than 800 million pairs. This is larger than any program used as a benchmark in various reports. A precise points-to analysis for the entire JDK cannot be completed in reasonable amount of time. We [ 22 ] have solved this issue via a demand-driven (or client-based) analysis [ 23 ]. Here specific program points of interest are identified and only the information that is relevant to these specific program points are computed. First, identify program points which could represent potential violations of confidentiality and integrity constraints. Second, we compute the necessary information that can influence the behaviour at the program points identified in the first step. The judicious use of a demand-driven approach that combines program slicing and staging of analysis, the relevant points-to information can be computed. The time taken for the security analysis is less than 5% of the time taken for the points-to analysis.
We present a concrete example from the OpenJDK7-b147 in Fig. 16 hat illustrates the use of our analysis. As the methodClass.forName is a caller-sensitive method any call to it from within the library is security-sensitive and hence no unsanitised tainted value should reach it. The method ClassLoader.findClass is defined in the library and calls Class.forName. If the call tocheckPackageAccess (which eventually calls checkPermission and hence can be viewed as a sanitiser) on Line 2 is omitted, there is an integrity violation as a tainted value reaches a caller-sensitive method. See [ 19 ] to see how such an omission can lead to security issues.
Example from java.lang.ClassLoader in the OpenJDK
In this article we have described the key concepts related to information flow security and shown how points-to analysis can be used in the static analysis of information flow properties.
We related information flow properties like confidentiality and integrity with points-to analysis. First, we showed a straightforward design of taint and escape analyses using points-to analysis. Then we showed that the integrity violations can be detected by using taint analysis in presence of sanitisation. Similarly we also showed that the confidentiality violations can be detected using escape analysis in presence of declassification.
Finally, we demonstrated these analyses on JDK using points-to analysis in the context of Java Secure Coding Guidelines. We have shown how the conditions required by the various guidelines can be expressed in terms of dataflow, escape and taint analyses.
- Gong, L.: ‘Java security architecture revisited’, .
- Karjoth, G.: ‘An operational semantics of Java 2 access control’. Proc. of the 13th Computer Security Foundations Workshop, 2000, pp. 224–232.
- Banerjee, A., Naumann, D.A.: ‘Stack-based access control and secure information flow’,
- Sabelfeld, A., Myers, A.C.: ‘Language-based information-flow security’, .
- Hedin, D., Sabelfeld, A.: ‘A perspective on information-flow control’. Software Safety and Security – Tools for Analysis and Verification, volume 33 of NATO Science for Peace and Security Series – D: Information and Communication Security, 2012, pp. 319–347.
- Java Product Group 2014: ‘Secure coding guidelines for Java SE’, 2014. Available at http://www.oracle.com/technetwork/java/seccodeguide-139067.html. Document version 5.0, published 2 April 2014, last updated 25 September 2014.
- Livshits, V.B., Lam, M.: ‘Finding security vulnerabilities in Java applications with static analysis’. Proc. of the USENIX Security Symp., 2005. Available at https://citeseer.ist.psu.edu/livshits05finding.html.
- Pistoia, M., Chandra, S., Fink, S.J., Yahav, E.: ‘A survey of static analysis methods for identifying security vulnerabilities in software systems’,
- Graf, J., Hecker, M., Mohr, M.: ‘Using JOANA for information flow control in Java programs – a practical guide’. Proc. of the 6th Working Conf. on Programming Languages (ATPS), Lecture Notes in Informatics (LNI) 215 , Berlin/Heidelberg, 2013, pp. 123–138.
- Ryder, B.G.: ‘Dimensions of precision in reference analysis of object-oriented programming languages’. Proc. of the 12th Int. Conf. on Compiler Construction, 2003, pp. 126–137.
- Milanova, A., Rountev, A., Ryder, B.G.: ‘Parameterized object sensitivity for points-to analysis for Java’,
- Bravenboer, M., Smaragdakis, Y.: ‘Strictly declarative specification of sophisticated points-to analyses’. Proc. of the 24th ACM SIGPLAN Conf. on Object-Oriented Programming Systems Languages and Applications, OOPSLA ‘09, 2009, pp. 243–262. ISBN 978-1-60558-766-0. doi: http://doi.acm.org/10.1145/1640089.1640108 .
- Smaragdakis, Y., Bravenboer, M.Lhoták, O.: ‘Pick your contexts well: Understanding object-sensitivity’. Proc. of the 38th Annual ACM SIGPLAN-SIGACT Symp. on Principles of Programming Languages, POPL ‘11, 2011, pp. 17–30. ISBN 978-1-4503-0490-0. doi: http://doi.acm.org/10.1145/1926385. 1926390. http://doi.acm.org/10.1145/1926385.1926390.
- Smaragdakis, Y., Kastrinis, G., Balatsouras, G.: ‘Introspective analysis: Context-sensitivity, across the board’. Proc. of the 35th ACM SIGPLAN Conf. on Programming Language Design and Implementation (PLDI), 2014, pp. 485–495.
- Abiteboul, S., Hull, R., Vianu, V.: ‘
- Smaragdakis, Y., Balatsouras, G.: ‘Pointer analysis’,
- Prabhu, P., Shankar, P.: ‘Field flow sensitive pointer and escape analysis for java using heap array SSA’. Proc. of the 2008 Int. Symp. on Static Analysis (SAS), 2008 ( LNCS, 5079).
- Gong, L., Ellison, G., Dageforde, M.: ‘Inside Java 2 Platform Security’. The Java Series , Addison Wesley, 2003.
- Cifuentes, C., Gross, A., Keynes, N.: ‘Understanding caller-sensitive method vulnerabilities: A class of access control vulnerabilities in the Java platform’. Proc. of the SOAP Workshop, 2015, pp. 7–12.
- Nielson, F., Nielson, H.R., Hankin, C.: ‘
- Allen, N., Krishnan, P., Scholz, B.: ‘Combining type-analysis with points-to analysis for analyzing Java library source-code’. Proc. of the SOAP Workshop, 2015a, pp. 13–18.
- Allen, N., Scholz, B., Krishnan, P.: ‘Staged points-to analysis for large code bases’. Compiler Construction, 2015b ( LNCS, 9031) , pp. 131–150.
- Sridharan, M., Gopan, D., Shan, L., Bodik, R.: ‘Demand-driven points-to analysis for Java’. Proc. of the 20th Annual ACM Conf. on Object-Oriented Programming, Systems, Languages, and Applications (OOPSLA), 2005, pp. 59–76. Available at http://doi.acm.org/10.1145/1094811.1094817.
© Oracle Corporation
First published on Engineering & Technology Reference 14 April 2016