{'fraction_non_alphanumeric': 0.03195048511207762, 'fraction_numerical': 0.009785881565741051, 'mean_word_length': 4.797090909090909, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 2, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
Automated Verification of Integer Overflow

Integer overflow accounts for one of the major source of bugs in software. Verification systems typically assume a well defined underlying semantics for various integer operations and do not explicitly check for integer overflow in programs. In this paper we present a specification mechanism for expressing integer overflow. We develop an automated procedure for integer overflow checking during program verification. We have implemented a prototype integer overflow checker and tested it on a benchmark consisting of already verified programs (over 14k LOC). We have found 43 bugs in these programs due to integer overflow.


INTRODUCTION
Numerical errors in software are quite common and yet are ignored by most verifications systems. Integer overflow in particular has been among the top 25 software bugs (Christey et al., 2011). These errors can lead to serious failures and exploitable vulnerabilities. Program verification helps to build reliable software by ensuring that relevant properties of can be validated. In Hoare logic style program verification we typically specify programs using pre and post conditions. The verifier assumes an underlying well defined semantics and generates proofs of correctness of program. Most verification systems do not check for errors due to undefined behaviors in programs. In C/C++ the integer operations may lead to undefined behaviors as specified by the standard. Undefined behaviors in the C/C++ specification lead to confusion among programmers. Moreover many programmers expect wrap around behavior for integer overflow (Dietz et al., 2012) and may intentionally write code that leads to such overflows. The code written with undefined (in the language specification) intentional overflows is not guaranteed to be portable and the behavior may depend on the optimizations used in various compilers.
It is no surprise that automated verifiers typically assume a well defined semantics for various integer operations. However in order to increase the completeness of verification it is desirable to specify and verify integer overflow. The starting point of this work is the HIP/SLEEK verification system  based on separation logic. HIP/SLEEK system can do automated verification of shape, size and bag properties of programs . We extend the domain of integers (extended number line) with two logical infinite constants ∞ and −∞, corresponding to positive and negative infinity respectively. Even though this kind extension of integers is common in libraries for programming languages for portability reasons, it is eventually typically mapped to a fixed value for a particular underlying architecture (32-bit or 64-bit). In a verification setting we find it better to enrich the underlying specification logic with these constants and reason with them automatically during entailment. This mechanism allows us to specify intentional and unintentional integer overflow in programs. In particular our key contributions are • A specification mechanism for integer overflows using logical infinities • Entailment procedure for handling logical infinities The rest of the paper is structured as follows. In the next section, we motivate our approach with a few examples. Then we present our specification language with logical infinities. This specification language is used to describe automated verification with integer overflow checking. We also formulate some soundness properties of our system. In the experiments section we present our implementation with a benchmark of already verified programs. We describe some related work and finally we conclude in the last section.

MOTIVATING EXAMPLES
We illustrate the integration of integer overflow checking in a verification system by means of few examples. The following function increments the value passed to it. void ex1(int n) requires n≥0 ensures res=n+1; { return n + 1; } If the value of n that is passed to this function is the maximum value that can be represented by the underlying architecture this program will lead to an integer overflow. In order to avoid dealing with absolute values of maximum and minimum integers we introduce a logical constant ∞ in the specification language. With this constant it is possible to write the specification for the function to avoid integer overflow.
void ex2(int n) requires 0≤n + 1<∞ ensures res=n+1; { return n + 1; } Another benefit of adding this constant to the specification language is that it allows users to specify intentional integer overflow. A recent study (Dietz et al., 2012) has found intentional integer overflow occurs frequently in real codes. We allow a user to express integer overflow using ∞ constant where such behavior is well defined. The following example shows how to specify intentional overflow.
void ex3(int n) requires n≥0 ensures (n+1<∞∧res=n+1) ∨ (n+1≥∞∧(true) ioc ); { return n + 1; } In this example we use the error calculus from (Le et al., 2013) to specify integer overflow with an error status ( ioc ). This error status is verified and propagated during entailment. Details of the error validation and localization mechanism are given in (Le et al., 2013). Use of logical infinity constants (∞) enable us to specify intentional integer overflow as an explicit error scenario in the method specification. Another benefit of using an enhanced specification mechanism (with ∞ constants) is that we can integrate integer overflow checking in an expressive logic like separation logic. This addresses two major problems faced by static integer overflow checkers -tracking integer overflow through heap and integer overflows inside data structures. As an example consider the following method which returns the sum of values inside a linked list. We can specify the linked list using a predicate in separation logic (ll). In the predicate definition we use ∞ constant to express the fact that the sum of values in the list cannot overflow. With this predicate we can now write the pre/post condition for the function ex4. During verification we can now check that the sum of values of linked list will not lead to an integer overflow. A common security vulnerability that can be exploited using Integer overflow is the buffer overrun. The following example (ex5) shows how two character arrays can be concatenated. We express the bounds on the domain of arrays using a relation dom. This program can lead to an integer overflow if the sum of the size of two arrays is greater than the maximum integer that can be represented by the underlying architecture. By capturing the explicit condition under which this function can lead to an integer overflow ( ioc ) we can verify and prevent buffer overrun. We again use the ∞ logical constant in the precondition to specify the integer overflow. if(len1 + len2 > 256) return − 1; memcpy(buf, buf1, len1); memcpy(buf + len1, buf2, len2); buf1 = buf; return 0; } Using ∞ constant as part of the specification language we can represent various cases of integer overflows in a concise manner. In this way we also avoid multiple constants like INT MAX, INT MIN etc., typically found in header files for various architectures. When compared to other approaches, this specification mechanism is more suited to finding integer overflows during verification.
Exploitable vulnerabilities caused by integer overflows can also be prevented by specifications preventing overflow using ∞. The following example (taken from (Dowd et al., 2006)) shows how integer overflow checking can prevent network buffer overrun. For brevity we show only part of the functions and omit the specification for the method as well. The function ex6 reads an integer from the network and performs some sanity checks on it. First, the length is checked to ensure that it's greater than or equal to zero and, therefore, positive. Then the length is checked to ensure that it's less than MAXCHARS. However, in the second part of the length check, 1 is added to the length. This opens a possibility of the following buffer overrun: A value of INT MAX passes the first check (because it's greater than 0) and passes the second length check (as INT MAX + 1 can wrap around to a negative value). read() would then be called with an effectively unbounded length argument, leading to a potential buffer overflow situation. This situation can be prevented by using the specifications given for the network get int method that ensures that length is always less than ∞.

SPECIFICATION LANGUAGE
We present the specification language of our system which is extended from  with the addition of a constant representing logical infinity. The detailed language is depicted in figure 1. Φ pr * → Φ po captures a precondition Φ pr and a postcondition Φ po of a method or a loop. They are abbreviated from the standard representation requires Φ pr and ensures Φ po , and formalized by separation logic formula Φ. In turn, the separation logic formula is a disjunction of a heap formula and a pure formula (κ∧π). The pure part π captures a rich constraint from the domains of Presburger arithmetic (supported by Omega solver (Pugh, 1992)), monadic set constraint (supported by MONA solver (Klarlund and Moller, 2001)) or polynomial real arithmetic (supported by Redlog solver (Dolzmann and Sturm, 1997)). Following the definitions of separation logic in (Ishtiaq and O'Hearn, 2001;Reynolds, 2002), the heap part provides notation to denote emp heap, singleton heaps →, and disjoint heaps * .
The major feature of our system compared to (Ishtiaq and O'Hearn, 2001;Reynolds, 2002) is the ability for user to define recursive data structures. Each data structure and its properties can be defined by an inductive predicate pred, that consists of a name p, a main separation formula Φ and an optional pure invariant formula π that must hold for every predicate instance. In addition to the integer constant k we now support a new infinite constant denoted by ∞. This enables us to represent positive and negative infinities by ∞ and −∞ respectively. For the following discussion we assume the existence of an entailment prover for separation logic (like ) and a solver for Presburger arithmetic (like (Pugh, 1992)). We now focus only on integrating automated reasoning with the new infinite constant ∞ inside these existing provers.
where p is a predicate name; v, w are variable names; c is a data type name; k is an integer constant;

Figure 1. The Specification Language
An entailment prover for the specification language is used to discharge proof obligations generated during forward verification. The entailment checking for separation logic formulas is typically represented  as follows.
This attempts to prove that Φ 1 entails Φ 2 with Φ r as its frame (residue) not required for proving Φ 2 . This entailment holds, if Φ 1 =⇒ Φ 2 * Φ r . Entailment provers for separation logic deal with the heap part (κ) of the formula and reduce the entailment checking to satisfiability queries over the pure part (π). We now show how this reasoning can be extended to deal with the new constant representing infinity (∞). A satisfiability check over pure formula with ∞ is reduced to a satisfiability check over a formula without ∞ which can be discharged by using existing solvers (like Omega). In order to eliminate ∞ from the formula we take help of the equisatisfiable normalization rules shown in figure 2 and proceed as follows.
We start with substituting any equalities with ∞ constants then we apply the normalization rules. The normalization rules eliminate certain expressions containing ∞ based on comparison with integer constants (k) and variables (v). We show rules for both ∞ and −∞ in figure 2. In the normalization rules we use a 1 =a 2 as a shorthand for ¬(a 1 =a 2 ). During normalization, we may generate some equalities involving ∞ (in [NORM−VAR−INF]). In that case, we normalize again after substituting the new equalities in the pure formula. Once no further equalities are generated we eliminate the remaining ∞ constant if any by replacing it with a fresh integer variable v ∞ in the pure formula. The pure formula now does not contain any infinite constants and a satisfiability check on the formula can now be done using existing methods.

Figure 2. Equisatisfiable Normalization
Enriching the specification language with infinite constants is quite useful as it allows users to specify properties (integer overflows) using ∞ as demostrated in the motivating examples. The underlying entailment procedure can automatically handle ∞ by equisatisfiable normalization.

VERIFICATION WITH INTEGER OVERFLOW
Our core imperative language is presented in figure 3. A program P comprises of a list of data structure declarations tdecl * and a list of method declarations meth * (we use the superscript * to denote a list of elements). Data structure declaration can be a simple node datat or a recursive shape predicate declaration pred as shown in figure 1.
A method is declared with a prototype, its body e, and multiple specification mspec * . The prototype comprises a method return type, method name and method's formal parameters. The parameters can be passed by value or by reference with keyword ref and their types can be primitive τ or user-defined c. A method's body consists of a collection of statements. We provide basic statements for accessing and modifying shared data structures and for explicit allocation of heap storage. It includes: 1. Allocation statement: new c(v * ) 2. Lookup statement: For simplifying the presentation but without loss of expressiveness, we just provide one-level lookup statement v.f rather than v.f 1 .f 2 .
3. Mutation statement: v 1 .f := v 2 In addition we provide core statements of an imperative language, such as semicolon statement e 1 ; e 2 , function call mn(v * ), conditional statement if v e 1 e 2 , and loop statement while v e (mspec) * . Note that for simplicity, we just allow boolean variables (but not expression) to be used as the test conditions for conditional statements and loop statement must be annotated with invariant through mspec * . To illustrate some of the basic operations on integers in the language we also show the addition operation between two integers (unsigned and signed) in figure 3 as k We now present the modifications needed to do forward verification with interger overflow. The core language used by our system is a C-like imperative language described in figure 3. The complete set of forward verification rules are P ::= tdecl * meth * tdecl ::= datat | pred datat ::= data c { field * } field ::= t v t ::= c | τ τ : Figure 3. A Core Imperative Language as given in . We use P to denote the program being checked. With the pre/post conditions declared for each method in P, we can now apply modular verification to its body using Hoare-style triples ⊢ {∆ 1 }e{∆ 2 }. We expect ∆ 1 to be given before computing ∆ 2 since the rules are based on a forward verifier. To capture proof search, we generalize the forward rule to the form ⊢ {∆ 1 }e{Ψ} where Ψ is a set of heap states, discovered by a search-based verification process . When Ψ is empty, the forward verification is said to have failed for ∆ 1 as prestate. As most of the forward verification rules are standard (Nguyen et al., 2007), we only provide those for method verification and method call. Verification of a method starts with each precondition, and proves that the corresponding postcondition is guaranteed at the end of the method. The verification is formalized in the rule [FV−[METH]]: At a method call, each of the method's precondition is checked, ∆⊢ κ V,I ρΦ i pr * Ψ i , where ρ represents a substitution of v j by v ′ j , for all j = 1, .., n. The combination of the residue Ψ i and the postcondition is added to the poststate. If a precondition is not entailed by the program state ∆, the corresponding residue is not added to the set of states. The test Ψ ={} ensures that at least one precondition is satisfied. Note that we use the primed notation for denoting the latest value of a variable. Correspondingly, In order to integrate integer overflow checking with automated verification we first translate the basic operations in the core language (like integer addition) to method calls to specific functions which do integer overflow checking. In this paper we illustrate the verification using only the addition overflow, however similar translations can be done for other operators like multiplication (Moy et al., 2009) etc.. The addition operation for unsigned integers k uint 1 + k uint 2 is translated to the method uadd whose specification is given below. int uadd(uint k 1 , uint k 2 ) requires k 1 +k 2 >∞ ensures (true) ioc ; requires k 1 +k 2 ≤∞ ensures res=k 1 +k 2 ; The addition of unsigned integers overflows when their sum is greater than ∞. The case of signed integer overflow has several cases. We translate addition of signed integers to the method add. The specification of the add method covers all the cases for signed integer overflow as detailed in (Dannenberg et al., 2010).

SOUNDNESS
In this section we outline the soundness properties of our entailment procedure with infinities and the forward verifier with integer overflow checking. We assume the soundness of the underlying entailment checker and verifier .

Lemma 1. (Equisatisfiable Normalization)
If π π norm then SAT (π) =⇒ SAT (π norm ) and SAT (π norm ) =⇒ SAT (π) Proof We sketch the proof for each normalization rule given in figure 2. Hence the normalization preserves satisfiability of pure formulas. We can prove the other rules in [NORM−CONST−INF] similarly.
case [NORM−VAR−INF]: We sketch the proof for the following rule, Hence the normalization preserves satisfiability of pure formulas. Other rules from [NORM−VAR−INF] can be proven similarly.
case [NORM−MIN−MAX]: We sketch the proof for the following rule, Hence the normalization preserves satisfiability of pure formulas. Other rules from [NORM−MIN−MAX] can be proven similarly.

Lemma 2. (Soundness of Integer Overflow Checking) If the program e has an integer overflow ( ioc ) then, with forward verification
Provided all basic operators on integers in the program are translated to method calls that check for integer overflows. The soundness of integer overflow checking follows from lemma 1 and the soundness of error calculus (Le et al., 2013).
The soundness of heap entailment and forward verification with separation logic based specifications is already established in . Lemma 1 establishes that the normalization rules indeed preserve the satisfiability of pure formulas. Lemma 2 then shows that the integer overflow checking with forward verification is sound. If the program has an integer overflow the forward verification with integer overflow checking detects it.

EXPERIMENTS
We have implemented our approach in an OCaml prototype called HIPioc 1 evaluate automated verification using logical infinities (∞) we created benchmark of several programs that use infinite constants as sentinel values in searching and sorting. As an example the following predicate definition of a sorted linked list uses ∞ in the base case to express that the minimum value in an empty list is infinity. data {int val; node next} Sortedll root, min ≡(root=null∧min=∞)∨ ∃ q · (root →node min, q * Sortedll q, minrest )∧min<minrest In addition, HIPioc allows us to do integer overflow checking of programs during verification. We have run HIPioc on several existing verification benchmarks which contain different kinds of programs. The benchmarks include many examples of programing manipulating complex heap, arrays, concurrency (barriers and variable permissions) and some programs taken from real software (SIR). The results are shown in the table below. Sorting(with ∞) are the programs which use ∞ as sentinel value in predicate definitions as described above and do not contain integer overflows. Comparing the times between HIPioc and previous version we see that the verification with ∞ in general adds some overhead.

Benchmark
LOC In total we found 43 integer overflows in these programs. Since these programs were already verified by using automated provers we notice that integer overflows are prevalent even in verified software. As our verification system is based on over approximation (sound but not complete), it can lead to false positives when finding integer overflows. In practice, we see that only 1 example in the experiments we conducted contained a false positive. The time taken to do verification of programs without and with integer overflow checking shows that our technique can be applied to do integer overflow checking of programs during verification with modest overhead.

RELATED WORK
There has been considerable interest in recent years to detect and prevent integer overflows in software (Cotroneo and Natella, 2012). Dietz et al. (Dietz et al., 2012) present a study of integer overflows in C/C++ programs. They find out that intentional and unintentional integer overflows are prevalent in system software. Integer overflows often lead to exploitable vulnerabilities in programs (Christey et al., 2011). In this paper we presented a method to detect unintentional integer overflows and provided a mechanism to specify intentional integer overflows. Program transformations (Coker and Hafiz, 2013) can be used to guide the programmer and aid in refactoring the source code to avoid integer overflows. Our focus is on specification of intentional integer overflows which helps make the conditions under which the program may use an integer overflow explicit. It also aids in automated verification as such cases can be validated as error scenarios for the program.
Most existing techniques for detecting integer overflows are focused on dynamic checking and testing of programs (Molnar et al., 2009;Wang et al., 2009;Chen et al., 2009;Brumley et al., 2007). Dynamic analysis suffers from the path explosion problem and although several improvements in constraints solving have been proposed (Sharma, 2012(Sharma, , 2013 the approach cannot guarantee the absence of integer overflows. There are not many verification or static analysis tool that can do integer overflow checking. KINT (Wang et al., 2012) is a static analysis tool which can detect integer overflows by solving constraints generated from source code of programs. Another static analysis based approach by Moy et al. (Moy et al., 2009) uses the Z3 solver to do integer overflow checking as part of the PREFIX tool (Bush et al., 2000). A certified prover for presburger arithmetic extended with positive and negative infinities has been described in (Sharma, 2015;Sharma et al., 2015).
Our focus in this paper is on integrating integer overflow checking with program verification to improve the reliability of verified software. Dynamic techniques may not explore all paths in the programs while static techniques suffer form loss of precision in tracking integer overflows. Our specification mechanism allows us to integrate integer overflow checking inside a prover for specification logic. This allows us to track integer overflows through the heap and inside various data structures. The benefit of this integration is that we can detect numeric integer overflow errors in programs with complex sharing and heap manipulation.

CONCLUSION
Integer overflows are a major source of errors in programs. Most verification systems do not focus on the underlying numeric operations on integers and do not handle integer overflow checking. We presented a technique to do integer overflow checking of programs during verification. Our specification mechanism also allows expressing intentional uses of integer overflows. We implemented a prototype of our proposal inside an existing verifier and found real integer overflow bugs in benchmarks of verified software.