• Keine Ergebnisse gefunden

5.7 Handling of Pointers

5.7.2 Resolution

We handle all memory areas pointed to by pointers as arrays with configurable size. By abstracting pointers to integers we achieve that constraints over pointers can be solved by a solver capable of integer arithmetics.

First, we introduce the definition and lemma that we need for the algorithm:

Definition 5.9. Each pointer pis defined by a pair of unsigned integers p= (A,x),

where

Acorresponds to a base address of the memory area where the pointerppoints into,

xis its offset (p=A+x).

Lemma 5.1. Expression

(p1ω p2) where

ω is a comparison operator,

p1and p2are pointers of the form pi= (Ai,xi),i=1,2 is equivalent to the following constraint:

A1==A2&&x1ω x2&& 0≤x1<dim(p1)&& 0≤x2<dim(p2) (5.1) where

A1==A2ensures, that p1and p2point to the members of the same memory portion,

x1ωx2reflects the pointer expression and

0≤xi<dim(pi),i=1,2,guarantees, that the pointer stays within the array bounds.

Proof. First we prove, that if(p1ω p2), then (5.1) holds. As was stated in the previous section, the behavior of(p1ω p2)is defined only ifp1andp2point to the members of the same array, henceA1==A2

and 0≤xi<dim(pi),i=1,2 hold. The result of comparison or subtraction of two pointers is dependent on the order of the array elements where the pointers point to. Offsetxirepresents exactly the position of the element in the array where the pointer points to, hence(x1ωx2)holds and consequently holds (5.1).

Now we prove, that if (5.1) holds, then(p1ω p2)holds too. SinceA1==A2and 0≤xi<dim(pi),i= 1,2 hold, it is ensured that corresponding pointers p1 and p2 point to the members of the same array, hence the behavior of the relationω is defined. If(x1ω x2)holds and the corresponding pointers point to the members of the same array, then, based on the observation that offset xi represents exactly the position of the element in the array where the pointer points to,(p1ω p2)holds.

Algorithm 17 shows the procedureresolvePointerVars(). This procedure is called at the end of the functionresolveConstraint()(see Algorithm 11) with the resolved path constraintΦ as input. The al-gorithm iterates over all atomic Boolean expressions of the given constraint and analyzes every variable of all these atoms. If a variable is a pointer, further analysis is required: it is distinguished between the situation when the atom is of a formp == NULLorp != NULLand all other expressions. If the pointer is compared withNULL, only its base address is relevant. In this case a new auxiliary variable var.A, corresponding to the base address of the pointervar, is created and the occurrence ofvarin the atomic expression ais replaced by it. When the atomic expression ais not a comparison with NULL, then it is a relation of pointers. This case is postponed and the variablesecondCheck, representing if the repeated analysis of the path constraint is required, is set totrue. This is done to ensure that the comparison of a pointer withNULLis not mistaken for relating to zero the base address of the pointer.

After all atoms were examined for comparison withNULLand if the repeated analysis is required, it is iterated one more time over all atomic Boolean expressions and their variables. This time all occurrences of comparisons withNULLin the path constraint are already eliminated, and, consequently, if a pointer variable is detected in an atom, this variable participates in a relation of pointers. As we have stated in Lemma 5.1, the relation of two pointers is equivalent to the expression (5.1). To build this expression two auxiliary variables are created: var.x, corresponding to the offset of the pointervarandvar.A, corresponding to its base address. The occurrence of varin the atomic expressionais replaced by the auxiliary variable responsible for the offset, and the variable related to the base address is stored in a set

i n o u t: exp e x p r e s s i o n which p o i n t e r v a r i a b l e s s h o u l d be r e s o l v e d i n p u t: mem c u r r e n t memory s p e c i f i c a t i o n

p r o c e d u r e r e s o l v e P o i n t e r V a r s (exp, mem) { ptrVars=/0;

secondCheck=f alse;

f o r e a c h ( atom a i n exp) { f o r e a c h( v a r i a b l e var i n a) {

i f(var i s a p o i n t e r ) {

i f(a == (var == NULL) a == (var ! = NULL) ) { c r e a t e v a r . A, υ( v a r . A) = υ(var);

r e p l a c e var by v a r . A i n atom a; } e l s e {

secondCheck=true;

} } } }

i f(secondChek) {

f o r e a c h ( atom a i n exp) { f o r e a c h( v a r i a b l e var i n a) {

i f(var i s a p o i n t e r ) {

c r e a t e v a r . x , υ( v a r . x ) = υ(var); exp=exp(v a r . x<dim(var));

r e p l a c e var by v a r . x i n atom a; c r e a t e v a r . A, υ( v a r . A) = υ(var); ptrVars=ptrVarsv a r . A ;

} } } }

/ / b u i l d b a s e a d d r e s s r e l a t i o n f o r e a c h( p . A i n ptrVars) {

p1 . A = n e x t t o p . A ; c=c∧( p . A == p1 . A) ) ; }

exp=expc; }

Algorithm 17: Resolution of pointer variables.

for further processing. Since the whole expressionexpis originated from the same guard condition, and since we are working with a GIMPLE code, where all expressions are broken down into expressions with no more than 3 operands [1], all pointers occurring in the expressionexpare related to each other. For this reason, at the end of the procedureresolvePointerVars()a constraintcis created, that requires, that all occurred pointers refer to the same array, which means that all their base addresses must be equal.

We illustrate the described approach on a simple example:

1 v o i d t e s t (char ∗p1 ,

2 char ∗p2 ) {

3 i f( p1 < p2 ) {

4 ERROR ;

5 }

6 }

To reach the line with an error, input pointersp1andp2should fulfill the guard conditionp1 < p2.

To focus on the discussed algorithm, we present the example in a simplified form. Sincep1andp2are inputs, the procedure resolveConstraint()cannot perform any further resolution. Thus, the following path constraint for the guard condition in line 3 is constructed:

p13<p23 p13==p10 p23==p20

wherep1iandp2iare pointers and therefore the solver is not capable to handle generated constraint. Now this constraint is passed to the procedureresolvePointerVars()from Algorithm 17.resolvePointerVars() analyzes the constraint atom by atom. First, all atoms are examined for comparison with NULL. As no such atom could be found, no transformations of the path constraint were performed. However, occurence of relation of pointers was detected, that is, the repeated analysis is required. During this analysis all atoms are examined one more time. First, relation atom(p13<p23)is examined. It contains two variables: p1 and p2, they are evaluated one after another. Variable p1 is a pointer. Thus, auxiliary variablesp1@baseAddressandp1@offsetof typeunsigned intare created, the occurrence ofp1 is replaced by the auxiliary variable representing its offset (p1@offset) and an additional constraint ensuring safety of array bounds is added. The same analysis is made for the variablep2. Atoms(p13==p10)and (p23==p20)are examined alike. At the end, additional constraints requiring equality of base addresses are added. The result is as follows:

p1@offset3 < p2@offset3 0 p1@offset3 < 10 0 p2@offset3 < 10 p1@offset3 == p1@offset0 0 p1@offset3 < 10 0 p1@offset0 < 10 p2@offset3 == p2@offset0 0 p2@offset3 < 10 0 p2@offset0 < 10 p1@baseAddress3 == p2@baseAddress3 p1@baseAddress3 == p1@baseAddress0 p2@baseAddress3 == p2@baseAddress0

Here the size for the auxiliary arrays is configured equal to 10, because this memory size makes condition p1<p2 feasible (any size≥2 would suffice). Note, that all occurrences of pointer variables are elim-inated and now all participating variables are of typeunsigned intso that the generated constraint can be passed to the solver. The solver returns the following solution (here the different versions of the

same variable are not listed for simplicity):

p 1 @ b a s e A d d r e s s = 2147483648 p 2 @ b a s e A d d r e s s = 2147483648 p 1 @ o f f s e t = 1

p 2 @ o f f s e t = 9

Now we illustrate how we interpret the obtained solution. We consider the calculated base address as a unique identifier of an auxiliary array: so, if the identifier appears for the first time, a new array is created. If the identifier is already known, the corresponding auxiliary array is taken. In our example identifier 2147483648 appears for the first time in the solution forp1@baseAddress, so the new array p1__autogen_arrayis created and the pointerp1is initialized with it. When the same identifier appears in the solution for p2@baseAddress, it is already known. Therefore,p2is also initialized withp1__autogen_array. Then offset values are processed and pointers are modified accordingly.

It results in the following test driver:

char p1 , p2 ;

char p 1 _ _ a u t o g e n _ a r r a y [ 1 0 ] ; u n s i g n e d i n t p 1 _ _ a u t o g e n _ o f f s e t ; u n s i g n e d i n t p 2 _ _ a u t o g e n _ o f f s e t ; p1 = p 1 _ _ a u t o g e n _ a r r a y ;

p2 = p 1 _ _ a u t o g e n _ a r r a y ; p 1 _ _ a u t o g e n _ o f f s e t = 1 ; p1 += p 1 _ _ a u t o g e n _ o f f s e t ; p 2 _ _ a u t o g e n _ o f f s e t = 9 ; p2 += p 2 _ _ a u t o g e n _ o f f s e t ;

With this test input the erroneous code in proceduretest()is uncovered. The generated test driver for this example as well as other generator output can be found in Appendix 4.