• Keine Ergebnisse gefunden

Handling of Arrays in remaining Cases

5.11 Handling of Arrays

5.11.2 Handling of Arrays in remaining Cases

The solver determinesΦas feasible and returns the following solution (we omit here the listing of the calculated values for local and auxiliary variables, since they do not affect the generated test case):

a@P [ 0 ] = −513 a@P [ 1 ] = −1 x = 1 y = 0

Based on the calculated solution, the generator constructs the following test driver:

i n t a ;

u n s i g n e d i n t x ; u n s i g n e d i n t y ; i n t a _ r t t _ a r r a y [ 1 0 0 ] ; i n t _ _ r t t _ r e t u r n ;

@ r t t B e g i n T e s t S t e p; {

y = 0 ; x = 1 ;

a _ r t t _ a r r a y [ 0 ] = 513;

a = a _ r t t _ a r r a y ; a _ r t t _ a r r a y [ 1 ] = −1;

a = a _ r t t _ a r r a y ;

@ r t t C a l l( _ _ r t t _ r e t u r n = t e s t ( a , x , y ) ) ; }

@rttEndTestStep;

As was already mentioned, CTGEN generates tests in RT-Tester syntax [44]. To make settings in the input array, the auxiliary arraya_rtt_arrayis created. Its values are set according to the calculated by the solver and the input parameterais set to this array. The values ofxandyare set appropriately to the solution. These settings satisfy the guard condition(a[x] > a[y])and, consequently, this test will cover the intended branch. The complete test script as well as the other outputs produced by the generator for the discussed example can be observed in Appendix 12.

C code GIMPLE representation

1 u n s i g n e d i n t aG [ 1 0 ] ;

2 i n t e x a m p l e (u n s i g n e d i n t x ) { 3 aG [ 0 ] = 1 ;

4 aG [ 3 ] = 2 ; 5 i f( aG [ x ] == 2 )

6 r e t u r n 1 ;

7 r e t u r n 0 ;

8 }

1 u n s i g n e d i n t aG [ 1 0 ] ;

2 i n t e x a m p l e (u n s i g n e d i n t x ) { 3 u n s i g n e d i n t D_1714 ;

4 . . .

5 aG [ 0 ] = 1 ; 6 aG [ 3 ] = 2 ; 7 D_1714 = aG [ x ] ; 8 i f( D_1714 == 2 ) {

9 . . .

10 }

11 }

We demonstrate here not the complete GIMPLE representation (and symbolic execution) but only the evaluation of the guard condition of theifstatement in line 6 of C code and the symbolic execution of the relevant statements. The complete generator output for this example is presented in Appendix 13.

For a better understanding of the procedure, we represent it as follows: we list the example code line by line and after each line we specify the memory items which were created by the symbolic execution of this line. The symbolic execution steps are numbered according to the line numbers of the GIMPLE representation listed above.

First, the memory is initialized. Initialization of globals and parameters:

1 u n s i g n e d i n t aG [ 1 0 ] ;

m1= (1,∞,&aG[0], 0, 320, int[10], aG0,true) 2 i n t e x a m p l e (u n s i g n e d i n t x )

m2= (2,∞,&x, 0, 32, unsigned int, x0,true) Subsequently, the stack initialization is done:

3 u n s i g n e d i n t D_1714 ;

m3= (3,∞,&D_1714, 0, 32, unsigned int, Undef, true) After the initialization is completed we proceed with the symbolic execution line by line:

5 aG [ 0 ] = 1 ;

m4= (4,∞,&aG[0], 0, 32, int[10], 1, true)

The insertion of the memory itemm4into the memory specification invalidates the memory item m1, so that nowm1is configured as follows:

m1= (1, 3, &aG[0], 0, 320, int[10], aG0,true)

Furthermore, the insertion of the memory item m4 triggers the construction of the new memory itemm5corresponding to the remains of the memory area of the memory itemm1not overlapping with the memory area ofm4:

m5= (4,∞,&aG[0], 32, 320, int[10], aG0,true) 6 aG [ 3 ] = 2 ;

m6= (5,∞,&aG[0], 96, 128, int[10], 2, true)

The insertion of the memory itemm6into the memory specification invalidates the memory item m5, so that nowm5is configured as follows:

m5= (4, 4, &aG[0], 32, 320, int[10], aG0,true)

Furthermore, the insertion of the memory item m6 triggers the construction of the new memory items m7 andm8 corresponding to the remains of the memory area of the memory itemm5 not overlapping with the memory area ofm6:

m7= (5,∞,&aG[0], 32, 96, int[10], aG0,true) m8= (5,∞,&aG[0], 128, 320, int[10], aG0,true) 7 D_1714 = aG [ x ] ;

m9= (6,∞,&D_1714, 0, 32, unsigned int, aG6[x6], true)

The insertion of the memory itemm9into the memory specification invalidates the memory item m3:

m3= (3, 5, &D_1714, 0, 32, unsigned int, Undef, true)

The next line of the example consists of anifstatementif(D_1714 == 2). This means that the evaluation of the guard condition (D_1714 == 2)is necessary. Before we start with the resolution algorithm, we summarize the current memory specification:

m1= (1, 3, &aG[0], 0, 320, int[10], aG0,true) m2= (2,∞,&x, 0, 32, unsigned int, x0,true)

m3= (3, 5, &D_1714, 0, 32, unsigned int, Undef, true) m4= (4,∞,&aG[0], 0, 32, int[10], 1, true)

m5= (4, 4, &aG[0], 32, 320, int[10], aG0,true) m6= (5,∞,&aG[0], 96, 128, int[10], 2, true)

m7= (5,∞,&aG[0], 32, 96, int[10], aG0,true) m8= (5,∞,&aG[0], 128, 320, int[10], aG0,true)

m9= (6,∞,&D_1714, 0, 32, unsigned int, aG6[x6], true) Now we process as defined by the functionresolveConstraint()(Algorithm 11):

1. Initialize the path constraint according to the guard condition:

Φ= (D_17146==2).

2. ResolveD_17146: find the memory item responsible forD_17146, this ism9. ResolveD_17146 according to the value of the item found:

D_17146==aG6[x6].

Now the algorithm resolveArrayExp() (see Algorithm 28) is invoked with D_17146 as var, aG6[x6]asval,Φascand our memory configuration asmem.

First the values of the auxiliary variablesoffsetStartandoffsetEndare calculated:

offsetStart = 32·x6

offsetEnd = 32·x6+32

Then the loop iterates over all memory items with the matching base address. These are the following: m8,m7,m6,m5,m4andm1. The validity period of the memory itemsm5andm1does not match the validity period ofaG6[x6]. Thus, onlym8, m7,m6 andm4 remain. We analyze them one by one:

m8: first the overlapping constraint is built

overlap= (128<32·x6+32) (320>32·x6) Since the valuem8refers to an input array, the array expression is built:

arrayExp=(D_17146==rttArrayRead(aG0, x6)) The array expression and overlapping constraint are summarized:

c1=(D_17146==rttArrayRead(aG0, x6)) (128<32·x6+32) (320>32·x6)

m7: first the overlapping constraint is built

overlap= (32<32·x6+32) (96>32·x6) Since the valuem7refers to an input array, the array expression is built:

arrayExp=(D_17146==rttArrayRead(aG0, x6)) The array expression and overlapping constraint are summarized:

c1=(D_17146==rttArrayRead(aG0, x6))(32<32·x6+32) (96>32·x6)

m6: first the overlapping constraint is built

overlap= (96<32·x6+32) (128>32·x6)

Since the valuem8does not refer to an input, the procedureresolveExp()(Algorithm 12) is invoked. It produces the following resolution:

c1=(D_17146==2)(96<32·x6+32) (128>32·x6)

m4: analog to the memory itemm6results in

c1=(D_17146==1)(0<32·x6+32) (32>32·x6)

Now we summarize all possible resolutions ofaG6[x6]and thus the resolution results in:

Φ= (D_17146==2)

((D_17146==rttArrayRead(aG0, x6))(128<32·x6+32) (320>32·x6) (D_17146==rttArrayRead(aG0, x6))(32<32·x6+32) (96>32·x6)

(D_17146==2)(96<32·x6+32) (128>32·x6) (D_17146==1)(0<32·x6+32) (32>32·x6)).

3. Resolvex6: find the memory item responsible forx6, this ism2. Resolvex6according to the value of the item found:

x6==x0. Add the resolution result to the path constraint:

Φ= (D_17146==2)

((D_17146==rttArrayRead(aG0, x6))(128<32·x6+32) (320>32·x6) (D_17146==rttArrayRead(aG0, x6))(32<32·x6+32) (96>32·x6)

(D_17146==2)(96<32·x6+32) (128>32·x6) (D_17146==1)(0<32·x6+32) (32>32·x6))

(x6==x0).

4. No unresolved symbols exist anymore. Thus, the resolution process stops and the constructed path constraint is passed to the solver.

After we have sketched the principle of proceeding of the algorithm, we will analyze it in more detail.

The resolution of an array assignment is performed by the procedure call resolveArrayExp(var,val,c,mem) Where

varis a versioned variable identifier. It indicates the variable, that has an array access as a value.

valis a versioned array expression.

cis a constraint that holds the result of the resolution process.

i n p u t: var v a r i a b l e i d e n t i f i e r which h a s an a r r a y e x p r e s s i o n a s v a l u e val a r r a y e x p r e s s i o n t h a t must be r e s o l v e d

mem c u r r e n t memory s p e c i f i c a t i o n i n o u t: c f e a s i b i l i t y c o n s t r a i n t

p r o c e d u r e r e s o l v e A r r a y E x p (var, val, c, mem) { offsetStart=ω(val)

offsetEnd=ω(val) + b i t s i z e(val); / / f i n d o u t c o r r e s p o n d i n g s e g m e n t S=σ(β(val),mem);

f o r e a c h m=last(S) downto head(S){

i f(m.v0υ(val)υ(val)m.v1m.a == β(val) ) { overlap= (m.o<offsetEnd)(m.l>offsetStart);

c1=m.c∧overlap;

i f(c1 i s f e a s i b l e ) {

i f(m.val i s n o t an i n p u t a r r a y ) { r e s o l v e E x p(var,m.val,c1,mem);

} e l s e {

arrayExp= (var==r t t A r r a y R e a d (m.val, g e t I d x(val)));

c1=c1arrayExp; }

c2=c2c1; }

} } c=cc2

}

Algorithm 28: Resolution of an array expression.

memis the current memory specification.

The Algorithm 28 shows the procedure for the resolution of an assignment of an array expression resolveArrayExp(). First the algorithm determines offset start and offset end of the memory area selected by the array expression. Then the algorithm finds all memory items referring to the array variable from the array expression val. By iterating over the found items the algorithm detects by which of them the validity period correlates with the version of the array access. As far as such an item is found, the overlapping of the memory segments corresponding to the memory item and to the array expression is examined. The overlapping condition is conjuncted with the feasibility constraint of the found memory item and is stored in constraintc1. When overlapping occurs and the feasibility constraint is feasible (i.e.

c1is feasible), the algorithm examines the value of the found memory item and, if the value does not refer to an input array, invokes the procedureresolveExp()(Algorithm 12). This procedure continues with the resolution process of the found value and stores the result in constraintc1. Otherwise, if the value of the item refers to an input array, the array expression resolving the variablevarto the element of arraym.val at index corresponding to the index of the array expression val by invocation of rttArrayRead() is built. This array expression is added to the feasibility constraint c1. The constraint c2 holds the disjunction of all constructedc1constraints and thus all possible resolutions of the array expressionval.

At the end of the algorithm, after all memory items with matching base address were explored, the resulting constraintc1is added to the constraintc, the overall outcome of the resolution process.

Now we return to the presented example and observe the test driver that was generated for the built path constraint Φ. The solver has determined Φ as feasible and returned the following solution (here we omit the listing of the calculated values for local and auxiliary variables since they do not affect the generated test case):

aG [ 1 ] = 2 x = 1

Based on the calculated solution, the generator constructs the following test driver:

e x t e r n u n s i g n e d i n t aG [ 1 0 ] ; u n s i g n e d i n t x ;

i n t _ _ r t t _ r e t u r n ;

@ r t t B e g i n T e s t S t e p; {

x = 1 ; aG [ 1 ] = 2

@ r t t C a l l( _ _ r t t _ r e t u r n = e x a m p l e ( x ) ) ; }

@rttEndTestStep;

As was already mentioned, CTGEN generates tests in RT-Tester syntax [44]. The values of parameterx and the global arrayaG[]are set according to the solution. These settings satisfy the guard condition (aG[x] == 2)and, consequently, this test will cover the intended branch. The complete test script as well as the other outputs produced by the generator for the discussed example are listed in Appendix 13.