Abstract:
Disclosed are typestate and lifetime dependency analysis methods for identifying bugs in C++ programs. Disclosed are an abstract representation (ARC++) that models C++ objects and which makes object creation/destruction, usage, lifetime and pointer operations explicit in the abstract model thereby providing a basis for static analysis on the C++ program. Also disclosed is a lifetime dependency analysis that tracks implied dependency relationships between lifetimes of objects, to capture an effective high-level abstraction for issues involving temporary objects and internal buffers, and subsequently used in the static analysis that supports typestate checking for the C++ program. Finally disclosed a framework that automatically genarates ARC++ representations from C++ programs and performs typestate checking to detect bugs that are specified as typestate automata over ARC++ representations.

Description:
TECHNICAL HELD 
       [0001]    This disclosure relates generally to the field of computer software systems and in particular to methods for the effective typestate and lifetime dependency analysis of software systems such as those written in C/C++. 
       BACKGROUND 
       [0002]    As is known, object oriented languages including Java and C++ are now extensively used to construct large-scale software and systems. As contemporary society increasingly relies on such software and systems, scalable techniques for checking the correctness, reliability and robustness of such software and systems becomes increasingly important. And while a number of scalable static analysis techniques for C and Java have been proposed, there has been comparatively little work done on the static analysis of C/C++ programs. Consequently the development of such techniques would represent a welcome addition to the art. 
       SUMMARY 
       [0003]    An advance is made in the art according to an aspect of the present disclosure directed to methods that identify correctness, performance, and maintenance issues (bugs) in C++ programs using bug patterns. Advantageously, a pattern-based method according to the present disclosure using simple patterns may detect even complex bugs involving lifetimes of objects. 
         [0004]    Viewed from one aspect, the present disclosure is directed to typestate and lifetime dependency analysis methods for identifying bugs in C++ programs. Disclosed are an abstract representation (ARC++) that models C++ objects and which makes object creation/destruction, usage, lifetime and pointer operations explicit in the abstract model thereby providing a basis for static analysis on the C++ program. Also disclosed is a lifetime dependency that tracks implied destructions between objects such that an effective high-level abstraction for issues involving temporary objects and internal buffers and subsequently used in the static analysis that supports typestate checking for the C++ program. Finally disclosed a framework that automatically genaerates ARC++ representations from C++ programs and performs typestate checking to detect bugs that are specified as typestate automata over ARC++ representations. 
     
    
     
       BRIEF DESCRIPTION OF THE DRAWING 
         [0005]    A more complete understanding of the present disclosure may be realized by reference to the accompanying drawings in which: 
           [0006]      FIG. 1  is a schematic diagram of an exemplary general purpose computer programmed to execute a method according to the present disclosure to find and correct a computer program; 
           [0007]      FIG. 2  is a schematic diagram showing a generic high-level abstract retation based program analysis according to an aspect of the present disclosure; 
           [0008]      FIG. 3  is a schematic diagram showing a number of main components employed duding abstract interpretation according to an aspect of the present disclosure; and 
           [0009]      FIG. 4  is a schematic diagram showing a high-level overview of a tool chain according to an aspect of the present disclosure. 
       
    
    
     DETAILED DESCRIPTION 
       [0010]    The following discussion and attached Appendix merely illustrates the principles of the disclosure. It will thus be appreciated that those skilled in the art will be able to devise various arrangements which, although not explicitly described or shown herein, embody the principles of the disclosure and are included within its spirit and scope. 
         [0011]    Furthermore, all examples and conditional language recited herein are principally intended expressly to be only for pedagogical purposes to aid the reader in understanding the principles of the disclosure and the concepts contributed by the inventor(s) to furthering the art, and are to be construed as being without limitation to such specifically recited examples and conditions. 
         [0012]    Moreover, all statements herein reciting principles, aspects, and embodiments of the disclosure, as well as specific examples thereof, are intended to encompass both structural and functional equivalents thereof. Additionally, it is intended that such equivalents include both currently-known equivalents as well as equivalents developed in the future, i.e., any elements developed that perform the same function, regardless of structure. 
         [0013]    Thus, for example, it will be appreciated by those skilled in the art that the diagrams herein represent conceptual views of illustrative structures embodying the principles of the invention. 
         [0014]    In addition, it will be appreciated by those skilled in art that any flow charts, flow diagrams, state transition diagrams, pseudocode, and the like represent various processes which may be substantially represented in computer readable medium and so executed by a computer or processor, whether or not such computer or processor is explicitly shown. 
         [0015]    In the claims hereof any element expressed as a means for performing a specified function is intended to encompass any way of performing that function including, for example, a) a combination of circuit elements which performs that function or b) software in any form, including, therefore, firmware, microcode or the like, combined with appropriate circuitry for executing that software to perform the function. The invention as defined by such claims resides in the fact that the functionalities provided by the various recited means are combined and brought together in the manner which the claims call for. Applicant thus regards any means which can provide those functionalities as equivalent as those shown herein. Finally, and unless otherwise explicitly specified herein, the drawings are not drawn to scale. 
         [0016]    Thus, for example, it will be appreciated by those skilled in the art that the diagrams herein represent conceptual views of illustrative structures embodying the principles of the disclosure. 
         [0017]    By way of some additional background, we note that as contemporary software development has increased a need for higher levels of abstractions in the software development industry, software programming teams have significantly shifted programming languages used to object-oriented languages such as Java or C++. The benefits of using an object-oriented language are well known and include—among others—maintainability, encapsulation, and inheritance. Despite the use of such languages however, it is nevertheless becoming more difficult to test and debug software due to large code bases and increasing complexity. 
         [0018]    Whereas, a large volume of work on verification has focused on C programs or Java programs, there has been comparatively little work on the verification of C++ programs. C++ has a number of distinguishing features that makes it difficult and—in some cases—impossible to use the verification techniques developed for other languages such as C and Java. 
         [0019]    More particularly, C++ is deliberately chosen for a software project due to its ability to fully interact with legacy C-based systems, including system-level, C-based, application programming interfaces (APIs). Therefore, development in C++ necessitates a mixed programming style combining features of high-level object-oriented constructs and lower-level C-based code. Moreover, the semantics of inheritance, virtual-function dispatch, and exceptions are different from other object-oriented languages such as Java. Consequently, there is a need to develop methods for the automatic verification and testing targeted at C++ programs. 
         [0020]    According to an aspect of the present disclosure, an algorithm is disclosed to find typical correctness, performance, and maintenance issues in C++ programs using bug patterns. As used herein, bug patterns are code idioms that are likely to be errors and describe coding practices that arise from misunderstanding of the language semantics, or simple and common mistakes. For example, absence of a copy constructor when the associated class has pointer fields is typically a bug. Similarly, dereferencing a Standard Template Library (STL) iterator without checking that it is not pointing within iterator bounds is most probably a bug. To find such bugs, our disclosure presents a framework for developers to specify bug patterns and disclose further a static analysis method to automatically detect the presence of such bug patterns in a software program. 
         [0021]    As may be readily appreciated by those skilled in the art, one of the peculiarities of C++ semantics is related to the lifetime(s) of temporary objects. More particularly, in C++, temporary objects are often created by a compiler and cause performance and correctness issues that are hard to find and understand. 
         [0022]    As is generally understood, temporary objects are unnamed objects created on a stack by the compiler. They are used during reference initialization and during evaluation of expressions including standard type conversions, argument passing, function returns, and evaluation of the throw expression. Performance bottlenecks can arise through the necessary creation and destruction of such temporary objects. Correctness issues can arise due to the complex lifetime semantics of temporary objects often leading to accesses of previously freed/destructed memory. 
         [0023]    The use of a mixed C and C++ programming (programs comprising both C and C++ programming) links the lifetimes of objects in complex ways. For example, consider a class that has a method ‘foo’ that returns an internal buffer and another method ‘bar’ that possibly reallocates the same internal buffer. Incorrect interactions of ‘foo’ and ‘bar’ can result in use-after-free errors. 
         [0024]    As we shall disclose, our pattern-based bug detection framework can advantageously detect even complex bugs involving lifetimes of objects using simple patterns. As noted above, temporary objects have an impact both on correctness and performance, and mixed C+ and C++ programming links object lifetimes in complex ways. 
         [0025]    Generally, the correctness issues related to object lifetimes are hidden during testing due—in part—to the fact that stale uses of object storage often occurs shortly after destruction of the object. Nevertheless, in an actual deployed production environment such short-term stale uses cause hard to find runtime errors, and memory corruption, leading to memory faults in the future. Furthermore, such memory corruption can also potentially be exploited by malicious user 
         [0026]    According to the present disclosure, a bug pattern is provided as a finite state machine (FSM) with a designated error state that is only reachable in the FSM for buggy code patterns. The finite state machine formalism is used fir this purpose. To make it easy to specify bug patterns, we annotate the given program with several high level notions such as ObjectCreation, ObjectDestruction, etc. We refer to these abstractions or annotations as ARC++. 
         [0027]    For the given bug pattern, we perform a call-summary-based static analysis that computes the set of reachable FSM states for each point in the program. Static analysis consists of a number of stages that are required for solving the problem. 
         [0028]    First, we need a finite representation for the potentially infinite set of heap and stack objects during static analysis. To this end, we describe an object abstraction based on access paths in the program and a notion of object clusters. As used herein, access paths correspond to the data access expressions in a C++ program. An object cluster represents a set of concrete objects that are potentially abased to each other. 
         [0029]    In some cases, the bug pattern may involve objects of more than one type. In such cases, we have defined a dependency graph that links objects that are related by the bug pattern. That is, an edge in the dependency graph between object o and p means that the state of one object is dependent on the other. Based on this notion, we build method summaries, where the behavior of methods and their side-effects on parameters and globals with respect to dependencies is captured. 
         [0030]    Subsequently, we perform a call-summary-based program analysis based on the object abstraction and dependency graph (if needed) and compute an over-approximation for the set of FSM states that are reachable at every program point. If any program point contains the error state, then it is reported to the user. 
         [0031]    One particularly interesting aspect of the present disclosure is observed is when the tracked dependency is related to the lifetime of objects. In such cases, if an operation, modification or destruction of object o causes the lifetime to expire for Object p, we introduce special liftetime dependency edges. Advantageously, these can be used to easily discover stale uses of objects after their lifetime has expired due to a modification of another object. 
         [0032]    Turning now to  FIG. 1 , there is shown in schematic block diagram form a general purpose computer which may be programmed to perform a method according to the present disclosure. Advantageously such methods are automated such that a computer program may be automatically analyzed such that a determination as to whether or not the computer program is correct—or not (contains bugs). Should such analysis determine faulty behavior(s), then such behavior(s) may be removed from the program resulting in its correct execution. 
         [0033]    According to the present disclosure, an abstract interpretation is performed and is shown schematically in  FIG. 2 . As is known, abstract interpretation is a well-known and understood technique to enable an efficient static program analysis. Abstract interpretation computes an over-approximation of reachable states—that is it computes a set of states which contains only those states that may be reached when the program is executed. This can be used to highlight potential errors in the program such as null-pointer accesses, buffer overruns, division-by-zero, etc. 
         [0034]    With reference now to  FIG. 3 , there is shown a schematic diagram which highlights some of the main components of a method according to the present disclosure. As depicted in that figure, the abstract interpretation technique maintains a work queue of control flow graph (CM) nodes that need to be further processed. For each CFG node, one of the following operations is generally performed: update a lattice element using a transfer function based on the assignments in the CFG node, perform a meet operation of two lattice elements, if the CFG node has multiple incoming parent nodes, perform widening of the lattice element in order to guarantee termination due to loops, or check whether a condition is potentially satisfied at the current node (interpretation of tests). After the operation has taken place, and if an update to the lattice element has occurred, the child CFG nodes may be added to the work-queue for additional processing. Notably a number of commonly used operations are not shown explicitly in  FIG. 3  to avoid unnecessarily cluttering that figure. Items not included for example, include computing the join of two lattice elements. 
         [0035]    Turning now to  FIG. 4 , there is shown a schematic block diagram of a tool chain according to the present disclosure. More specifically, and as shown schematically, a C or C++ program as provided as input to a front end for parsing C++ (GIRA) which includes two sub-modules named Simplifier (simplifies complex C++ expressions into simpler ones) and Clarifier (which makes implicit calls explicit). The output of GIRA is CILPP—an internal representation of C++. The GIRA frontend highlights the temporary object usage in a C++ program through full representation in our representation called CILPP. The next step in the chain is where the exception analysis is performed, with the creation of an IECFG after analysis. Then a CILPP abstraction is done resulting in the generation of ARC++. Finally, the IECFG, ARC++, CILPP and Bug Patterns are used together in the analysis module to find any bugs and output bug reports. 
         [0036]    The foregoing is to be understood as being in every respect illustrative and exemplary, but not restrictive, and the scope of the invention disclosed herein is not to be determined from the Detailed Description and the attached Appendix, but rather from the claims as interpreted according to the full breadth permitted by the patent laws. It is to be understood that the embodiments shown and described herein are only illustrative of the principles of the present invention and that those skilled in the art may implement various modifications without departing from the scope and spirit of the invention. Those skilled in the art could implement various other feature combinations without departing from the scope and spirit of the invention.