• Keine Ergebnisse gefunden

Symbolic Execution

4.2 Symbolic Values and Expressions

4.2.3 Arrays

i n t f u n (i n t a r r , i n t l e n , i n t x , i n t pos , i n t y , i n t pos2 , i n t z , i n t p o s 3 ) {

2 // w r i t e p h a s e i n t i ;

4 a r r [ pos ]=y ; i = 0 ;

6 w h i l e ( i <l e n ) { a r r [ i ]=x ;

8 i ++;

}

10 a r r [ p o s 2 ] = z ; // r e a d p h a s e

12 i=a r r [ p o s 2 ] ; i=a r r [ 0 ] ;

14 i=a r r [ 1 7 ] ; i=a r r [ pos ] ;

16 i=a r r [ p o s 3 ] ; r e t u r n i ;

18 }

Listing 4.3: Function to show problem with array accesses

assignment value for i.

x -> x0 p1 -> &x p2 -> &x p3 -> &x + 1 pp -> &p1 p4 -> &x i -> *p5

at specified indexes. After the write phase the read phase starts where some read operations are performed. Those read operations use fixed and variable indexes at known and unknown positions in the array.

Write Operations

First, we take a look at the different statements of the write phase of the program. For each relevant line, Table 4.3 contains the stored values after the relevant statement. The knowledge at fixed indexes (e.g. known integer indexes) is marked withf, while variable indexes (e.g. variables or expressions) are marked with v. Again, symbolic values are marked with0.

1. Writing to specific unknown position (line 4)

In line 4, the valuey0 is written to the array at index pos0. At that moment, the value is stored definitely at that index, without a condition.

2. Possible overwrite of former value (lines 5-9)

After the loop, which is illustrated in the lines 5 to 9, value x0 is written to the indexes 0 to 2. For a meaningful table size we assume that the loop is only executed 3 times. For details on loop unrolling, see Item 2 of Section 4.3.1. We now know the values for that fixed positions. However, the former stored value y0 is only correct at indexpos0, if pos0neither 0, 1 or 2. Because of this, conditions that specify the correctness of the value are stored for the former indexes.

3. Further assignment at unknown position (line 10)After the assignment state-ment in line 10, we know that valuez0is stored on positionpos20. Again, the former stored value are only correct, if the index doesn’t contain the same value as pos20.

Thus, a corresponding condition is added to all former stored entries.

It is important to notice that the last assignment at an index never depends on a condition. If there would already be a condition for the specified index, the conditions will be removed.

Read operations

As seen in the last part, the knowledge about variables might not be determinable defini-tively. Therefore, we can define different cases for the read phase of the program:

line kind index arr[index] condition

4 f - -

-v pos0 y0

-9 f

0 x0

-1 x0

-2 x0

-v pos0 y0 pos0 != 0 && pos0 != 1 && pos0 != 2

10 f

0 x0 0 != pos20

1 x0 1 != pos20

2 x0 2 != pos20

v pos0 y0 pos0 != 0 && pos0 != 1 && pos0 != 2 && pos0 != pos20

pos20 z0

-Table 4.3: -Table showing known values for local variables 1. Read from known index (line 12)

As we can see in the table, the value for the index variable is definitely defined, since it doesn’t contain any conditions for the specified index. Therefore, we can simply assign the symbolic value z0 to i. This works for fixed an variable indexes.

2. Read from former written fixed index (line 13)

In the next case, the program reads from an index where a value has been assigned.

However, this index has a condition, since more assignments happened after the assignment of the value. Therefore, the read access can lead to three different cases.

The assignment value is eitherx0, if 0 != pos20, or it can be the value of a variable index, if the stored variable index is equal to the read index, and all other conditions are true.

Therefore, the assignment value can bez0, if pos20would contain the value 0. Fur-thermore, it the value might bey0, if pos0is equal to0 and fulfills the other stored conditions pos0 != 0 && pos0 != 1 && pos0 != 2 && pos0 != pos20. As we can see in the defined conditions, there are two statements that make the condi-tion unsatisfiable, pos0 != 0 and pos0 == 0. Therefore, created paths for this case will be definitely unsatisfiable. However, those cases are generated, since the order of assignments is not stored, but only the conditions.

3. Read from never written fixed index (line 14)

This case is similar to the case before, but only two possible assignments are left:

i can either get the value z0, if pos20 == 17 or y0, if pos0 != 0 && pos0 != 1

&& pos0 != 2 && pos0 != pos2 && pos0 == 17. In this example, both cases are possible. If no condition is correct,iis set to a symbol which represents an unknown value.

4. Read from former written variable index (line 15)

In this case, we also have written to the read index before. Therefore, we got several cases. The variablei can get value x0, if pos0 is either0, 1 or2 and each of those indexes is not equal to pos20. Furthermore, i can get value y0, if pos0 != 0 &&

pos0 != 1 && pos0 != 2 && pos0 != pos20 && pos0 == pos0, or can be z0 if pos0 == pos20.

5. Read from never written variable index (line 16)

The last case handles the read from an unknown variable index. Such cases are handled like the one before, but it is also possible that an unknown value symbol has to be assigned, since we do not have a matching index.

As shown, there are several possibilities to assign a variable when it comes to array reads, if the index is not definitely known. To solve this problem, the following approach is used:

Before the array read statement, we split up the path into several cases for all possible values. This is done by introducing an additional if statement which leads to the required path split.

Figure 4.3 shows this process, referring to the mentioned case of line 13. The first part of the figure is the old order of statements. In the lower part, between the predecessor and the current array read statement, an if statement is introduced which represents the different cases.

The top node of the if contains the condition for the first possible value. If the condition is true, we know that the corresponding value should be used for the assignment. Therefore we create an assign statement for that index and the corresponding value. As mentioned, the last write to an array has no conditions, so the following read can be performed in the next statement without problems for the specific index. If the condition is false, the next if in the false path handles the next possible case.

Figure 4.3: Handling array read operations

kind index value condition f

0 z

-1 x 1 != pos2

2 x 2 != pos2

v pos y pos != 0 && pos != 1 && pos != 2 && pos != pos2 pos2 z pos2 != 0

Table 4.4: Updated known values for array read

Lets analyze the path for pos20 == 0. When we reach the statement in line 13, the illustrated if-statement is inserted. In this case, the first if would follow the false path, while the second if becomes true. Now, the assign statement is reached. When the assign statement is processes, it changes the value table to Table 4.4.

As we can see in the table, the next read operation has access the fixed value without conditions. Therefore, it can assign z toi for the case that pos20 equals 0.