• Keine Ergebnisse gefunden

Symbolic Execution

4. Handle statement list (lines 4-51, function recHandleList)

4.4 Application Scenarios

4.4.3 Model Abstraction

4.4.3.2 Approach

In order to create a state diagram, the following approach, shown in Listing 4.10, is used:

First, an initial node that contains the preconditions is added to the head of the workQueue (line 18). As long as the queue contains elements, the head element is used to perform a symbolic execution (lines 20-23). The solvable leafs of this execution, which represents follower states, are further analyzed. They can match the current state (line 29), an already reached state (line 48) or a completely new state (line 51). If a new state is discovered, it is added to the tail of the workQueue(line 52) and a transition is added to the graph (line 53). If the state has already been discovered, only a transition is added (line 49). If the same state is reached again, the combination of all negated and non-negated conditions is formed (line 38, function createCondCombinations), if it wasn’t already calculated before (line 36). Then, the analysis is performed again for every condition combination (lines 41-43) to get all possible states and transitions.

Due to this approach, the algorithm behaves as follows:

1 i n t f i l l ; i n t e r r o r ;

3 i n t c o u n t ; i n t pump ;

5 v o i d f u n (i n t empty , i n t f u l l , i n t r e s e t ) { i f ( e r r o r ) { // e r r o r

7 i f ( r e s e t ) { // r e s e t e r r o r =0;

9 c o u n t =0;

}

11 }e l s e{

i f ( f i l l ) { // f i l l

13 i f ( f u l l ) { // f u l l f i l l =0;

15 pump=0;

}

17 e l s e{ // f i l l i n g pump=1;

19 c o u n t=c o u n t +1;

i f ( count >3){ // t i m e o u t

21 e r r o r =1;

}

23 }

}

25 e l s e{// n o t f i l l i f ( empty ) {// empty

27 f i l l =1;

pump=1;

29 c o u n t =0;

}

31 e l s e{// i d l e pump=0;

33 }

}

35 }

}

Listing 4.9: Program for water tank simulation

2 s t a t e s = empty l i s t t r a n s i t i o n s = empty l i s t

4 c r o s s P r o d u c t = empty l i s t

6 f u n c t i o n a u t o m a t o n G e n e r a t i o n : c o n d i t i o n s = r e a d P r e c o n d i t i o n s

8 g l o b a l s = r e a d G l o b a l V a r i a b l e s

i n i t i a l = new S t a t e ( c o n d i t i o n s , g l o b a l s )

10 p e r f o r m ( i n i t i a l )

12 f u n c t i o n g e t S o l v a b l e L e a f s : p e r f o r m S y m b o l i c E x e c u t i o n

14 r e t u r n s o l v a b l e L e a f s

16 f u n c t i o n p e r f o r m ( i n t i a l S t a t e ) : workQueue = empty l i s t

18 workQueue = workQueue + i n i t i a l S t a t e

20 w h i l e ( workQueue has e l e m e n t ) : c u r r e n t = workQueue . head

22 workQueue . removeHead

s t a t e s = s t a t e s + c u r r e n t

24

l e a f s = c u r r e n t . g e t S o l v a b l e L e a v e s

26 n e w S t a t e s = t r a n s f o r m T o S t a t e s ( l e a f s )

28 f o r ( n e w St a t e i n n e w S t a t e s ) : i f ( n e w St a t e == c u r r e n t ) :

30 i f ( n e w S ta t e . v a l s != c u r r e n t . v a l u e s && sameCount < max ) : workQueue = workQueue + n e w St a t e

32 n e w T r a n s i t i o n = new T r a n s i t i o n ( c u r r e n t , n e w S t a te ) i f ( ! t r a n s i t i o n s c o n t a i n s n e w T r a n s i t i o n ) :

34 t r a n s i t i o n s = t r a n s i t i o n s + n e w T r a n s i t i o n

36 i f ( ! c r o s s P r o d u c t B u i l t c o n t a i n s c u r r e n t ) : c r o s s P r o d u c t B u i l t = c r o s s P r o d u c t B u i l d+c u r r e n t

38 c o n d i t i o n C o m b i n a t i o n s = c r e a t e C o n d C o m b i n a t i o n s ( c u r r e n t . c o n d i t i o n s ) n e w C o n d i t i o n S t a t e s = c r e a t e N e w S t a t e s ( c o n d i t i o n C o m b i n a t i o n s )

40

f o r ( n e w C o n d i t i o n S t a t e i n n e w C o n d i t i o n S t a t e s ) :

42 c o n d S o l v a b l e L e a f s = g e t S o l v a b l e L e a f s ( n e w C o n d i t i o n S t a t e ) c o n d S t a t e s = t r a n s f o r m T o S t a t e s ( c o n d S o l v a b l e L e a f s )

44

workQueue = workQueue + c o n d S t a t e s

46 t r a n s i t i o n s = c r e a t e T r a n s i t i o n s ( s t a t e , c o n S t a t e s )

48 e l s e i f ( ne w S t a t e i n s t a t e s | | n e w S t a te i n workQueue ) :

t r a n s i t i o n s = t r a n s i t i o n s + new T r a n s i t i o n ( c u r r e n t , n e w St a t e )

50

e l s e:

52 workQueue = workQueue + n e w St a t e

t r a n s i t i o n s = t r a n s i t i o n + new T r a n s i t i o n ( c u r r e n t , n e w S t a t e )

Listing 4.10: Pseudocode of automaton generation

Initially, the program is symbolically executed, which leads to several solvable paths. Those paths represent the first states after the initial state. For each of these paths, the global variables that are defined during the symbolic execution are collected and used as input for the next symbolic execution steps. When a state is already detected, the paths will not be followed any more. The process finishes when no more new states were detected.

As a first step, the program is analyzed without any preconditions or knowledge about values of global variables. With this prerequisites, every path in the code example is executable.

Now, each of these states is again used as source state for the next symbolic execution. This automaton is represented in Figure 4.8. The different states are named by a combination of true (T) and false (F), which show the branch taken in this state. The initial state is calledI.

Figure 4.8: Initial automaton without improvements

As the next step, a map with names for the states is added, which matches the comments in the listing. This step makes it easier to analyze and interpret the diagram. This automaton is shown in Figure 4.9.

Figure 4.9: Automaton after naming states

As an example, we take a look at the empty state: From the initial state, the empty state is reachable, since the path condition error == 0 && fill == 0 && empty != 0 is solvable.

This is a result of the lack of knowledge about values of input parameters and the global variables.

For the next symbolic execution, which finds the follower states of empty, assignments to global variables of the current state are used as preconditions. By executing the program with values error == 0, fill == 0 and empty != 0, the following settings are done: fill = 1, pump = 1 and count = 0. This again leads to several possible follower states. As visible, there is no self-circle, which means the system leaves the empty state immediately.

If the analysis continues with filling, the system behaves differently: No global variables are set. Therefore, the next state is only dependent on the input parameters.

Thus, the following transitions from filling are possible:

• If the input parameter doesn’t change, the same path will be executed again.

• If, for example, parameterfull becomes1 in the next cycle, the next state will befull.

An analogous behavior can be observed for other states.

Reaching the same state again would lead to an endless loop. Therefore, the algorithm handles such cases as follows:

• If the same state is reached again without any change in global variables, a transition cycle is introduced. Then, all possible changes of sensor values are computed by calculating the combination of all negated and non-negated conditions, and the symbolic execution is performed again. The source node is added to a list in order to prevent that the computation of condition combinations is performed multiple times.

• If any global variable changed, like a counter increment, the symbolic execution is per-formed again, and possibly reach another path after some iterations. If an upper retry limit is reached, this state is handled like the first case.

As a next step, values for the global variables are defined for the initial symbolic execution. By

setting values for global variables, not every path is reachable from the init state anymore.

Therefore, the state digram becomes significantly smaller.

In the example, all the global variables are set to 0. Therefore, only the states emptyand idle can be reached from the initial state. This is shown in Figure 4.10.

Again, looking at the filling state, the improvement can be recognized: Before setting the global variables, every state was a follower of filling, since no values for global variables were defined before filling as analyzed. Now, since global variables are defined, filling cannot be reached from the init state any more. When fillingis finally reached by the algorithm, global variables are set, and therefore only some states are possible followers. The resulting automaton is represented in Figure 4.10.

Figure 4.10: Automaton after initial setting of global variables

As we can see in Figure 4.10, from init two different states can be reached, since these states are reached by the same global variables, and only distinct by the inputs. Therefore, the initial conditions empty != 0, full == 0 and error == 0 are defined as preconditions for the first symbolic execution. By defining them, only the state empty can be reached frominit.

As soon as preconditions are defined, the automaton shows which sensor values have to change in order to move from a looping state to the next state. For example, Figure 4.11 shows that fillingonly transitions to full if full != 0 becomes true.

The current state diagram correctly represents the program. However, it is possible to define transitions that should not be included in the diagram. As an example, this is useful for

Figure 4.11: Automaton after adding conditions

the transitions from full to empty, since the tank has to transition to the idle state before reaching the empty state. Therefore, a definition is added that empty must not be 1 if full was 1 in the former state.

Figure 4.12 shows the state diagram with two removed transitions, full -> empty and empty -> full.

Figure 4.12: Automaton after including fobidden transitions

Chapter 5