Note that the name of a state machine is simply the name of its initial state. Also note that the transitions of the state machine are labelled with
actions.Such state machines are also known as labelled transition systems (LTSs). The transition from the initial state (S1) is labelled by an action
call_foo. This action encapsulates the externally observable event of library routine
foo being invoked. Such actions, with only names, are also called
basic actions.Back to TopReturn actions
As anyone familiar with the FSP will realize, we extend the FSP notation to express a special class of actions called
return actions. Return actions are of the form
return {expression} or
return {} where the former expresses the return of an integer value and the latter expresses returning a
void value. In a return action of the form
return {expression}, the
expression represents a condition satisfied by the return value. The return value itself is represented by the dummy variable
$0.For instance, the action
return {$0 < 5} represents the return of an integer value less than 5.
Note: The notation for return actions in version 1.0 is a
major departure from version 0.1. In version 0.1 we could write
return {10} to specify the return of 10 but there was no way to specify the return of a value less that 10. In version 1.0 this can be achieved simply by
return {$0 < 10}.Back to TopProcedure Block
We are now ready to express the fact that
S1 specifies the behavior of
my_proc when the first argument of
my_proc is equal to zero. In MAGIC, this can be achieved by the following
procedure block:
cproc my_proc {
abstract { abs_1 , ($1 == 0) , S1 };
}
Note the keywords
cproc and
abstract. The block keyword
cproc indicates that we are going to say something about a C procedure. It is followed by the name of the procedure and then by a set of statements enclosed within a pair of curly braces. Each such statement typically consists of an
statement keyword followed by other terms. The procedure whose name follows
cproc is often referred to as the scope procedure.
One such statement keyword is
abstract.This keyword indicates that we are expressing an abstraction relation between the scope procedure and an LTS. Note the guard
($1 == 0) where
$1 refers to the first argument. In general
$i can be used to refer to the
i-th argument of the scope procedure. Finally note that the abstraction statement has a name,
abs_1. For procedure blocks, the abstraction names are just placeholders and have no special significance. However, soon we will discuss
program blocks and for them, the names of abstraction statements will be of crucial importance.
The following LTS expresses the behavior of
my_proc when its first argument is not equal to zero:
In general, multiple procedure blocks can be combined into one as long as they have the same scope procedure. Also the order of statements within a procedure block is irrelevant. Thus, the above two procedure blocks together is equivalent to the following single procedure block:
MAGIC requires that the guards of abstraction statements for any scope procedure be mutually disjoint and complete (i.e. cover all possibilities of argument valuations). This is necessary to enable MAGIC to unambiguously identify the applicable abstraction in any given calling context of the scope procedure.
Back to TopSpecifying Library Routines
In order to construct a proper model for
my_proc MAGIC must know about the behavior of the library routines called by
my_proc. Let us assume that the actual code for
foo and
bar are unavailable. In such a case, MAGIC requires that the user supply appropriate
abstractions for these two routines. In particular, suppose that
foo and
bar are respectively abstracted by the LTSs
FOO and
BAR described below:
FOO = ( call_foo -> return {$0 == -1} -> STOP ).
BAR = ( call_bar -> return {$0 == 50} -> STOP ).
Then the following program blocks can be used to express the relation between
foo, bar and their abstractions.
cproc foo {
abstract { abs_3 , (1) , FOO };
}
cproc bar {
abstract { abs_4, (1), BAR };
}
Note that the guard in both abstraction statements is
1, which denotes
TRUE according to C semantics. This therefore means that under all calling contexts,
foo and
bar are abstracted by
FOO and
BAR respectively.
Also note that specifications and abstractions are syntactically identical. This makes sense because both abstractions and specifications are essentially asserting the same thing viz. that under a certain calling context, a procedure's behavior is subsumed by the behavior of an LTS. The only difference is that the assertion made by an abstraction can be
assumed to be true while the assertion made by a specification needs to be
validated. This has at least two significant consequences:
- Verifying Incomplete Code: In practice, one cannot assume that the actual code for each and every library routine used by a program will be available to the verifier. Hence being able to provide abstractions allows MAGIC to analyze such incomplete implementations. In effect, abstractions allow us to specify assumptions about the environment in which a program operates.
- Compositionality: Often programs are simply too big to be analyzed as one chunk of code. Abstractions allow us to decompose such large implementations into smaller, more manageable fragments. Fragments can be verified one at a time. While verifying one fragment, the abstractions of other fragments can be used as assumptions. The fact that specifications and abstractions are identical implies that they can naturally switch from one role to the other depending on which fragment is being verified.
Back to TopProgram Block
It is now time to specify the entire program that we want to verify. In our case the program is sequential, i.e. it has a single component consisting of the procedure
my_proc. The following
program block expresses the relation between our program and its specification:
cprog my_prog = my_proc {
abstract abs_5, {($1 == 0)}, S1;
abstract abs_6, {($1 != 0)}, S3;}
This looks a lot like a procedure block but there are some crucial differences. First, it begins with the keyword
cprog and not
cproc. This is followed by the name of the program (which is again a placeholder and does not serve any other purpose), an equal to sign and then a list of
procedure names. Intuitively these are the names of the procedures which execute in parallel and constitute the program. In the above block this list has a single procedure name viz.
my_proc, signifying that our program has just one component that executes
my_proc.
Following the list of procedure names we have a sequence of statements enclosed within curly braces. Just like procedure blocks, abstraction statements are used to provide specifications. But abstraction statements for program blocks are syntactically different. They do begin with the
abstract keyword, but the rest of it them is not enclosed within curly braces. Instead there are three components. The first is the name of the abstraction statement. This is used by MAGIC to identify the target abstraction to be validated. The second is a
list of guards, one for each component of the program. Each guard in the list expresses the beginning state of the corresponding component. In the above block, the list has just one element that expresses the starting context of
my_proc. Note that the list of guards is enclosed within curly braces. The third and final component is the name of the LTS which specifies the program.
Back to TopComments
You can use either C-style or C++ style comments in specification files.
/* this is a comment */
// so is this one
Back to TopRunning MAGIC
We are now ready to try out MAGIC. First save the C program in a file whose name must end with ".pp", say
my_proc.pp. Next save the specifications in another file whose name ends
with ".spec", for example
my_spec-1.0.spec. Finally run MAGIC:
$ magic --abstraction abs_5 my_proc.pp my_spec-1.0.spec --optPredMAGIC will try to validate the abstraction statement with name
abs_5. The
--optPred options tells MAGIC to perform counterexample guided abstraction refinement with predicate minimization. It is usually a good idea to always use this option. For details on other options that MAGIC can accept, look at the user's
manual. If all goes well, MAGIC should be able to successfully verify the abstraction and produce an output that ends with something like this:
conformance relation exists !!abstraction abs_5 is valid ...Simplify process destroyed ...terminating normally ...
Similarly you can try to verify
abs_6and MAGIC should be able to do it. If you look again at
my_spec-1.0.spec you will notice that we have added two more abstraction statements,
abs_7 and
abs_8, to the
my_prog block. They are similar to
abs_5 and
abs_6 except that the guard conditions have been switched. Clearly they are invalid specifications and MAGIC should be able to detect this. Try verifying
abs_7 by typing the following:
$ magic --abstraction abs_7 my_proc.pp my_spec-1.0.spec --optPred --ceShowActMAGIC should tell you that this is an invalid specification and further provide you with a counterexample. The output should look something like the following:
*******************************************
branch ( P0::x == 0 ) : [P0::x == 0] : TRUE
############ P0::epsilon ############
P0::y = foo ( ) : []
############ P0::epsilon ############
P0::y = foo ( ) : []
############ call_foo ############
P0::y = foo ( ) : []
############ {P0::y = [ -1 ]} ############
branch ( P0::y > 0 ) : [] : TRUE
############ P0::epsilon ############
return ( 10 ) : []
############ return { ! } ############
*******************************************
CE dag projections analysed ...
conformance relation does not exist !!
abstraction abs_7 is invalid ...
Simplify process destroyed ...
terminating normally ...Back to TopA Concurrent Example
Let us now verify a concurrent program. Our concurrent program will be very simple. It will be two copies of
my_proc executing in parallel. This is easy to understand because the resulting parallel program should behave exactly like a single copy of
my_proc (since our notion of parallel composition is idempotent). All we need to do is create a new program block specifying our example. Here is a sample
my_conc-1.0.spec.Notice that it has four abstraction statements
abs_9, abs_10, abs_11 and
abs_12 out of which the first two are valid while the last two are invalid
.We can try to verify
abs_9 by the following command:
$ magic --abstraction abs_9 my_proc.pp my_conc-1.0.spec --optPredThis should succeed. Likewise MAGIC should be able to prove that
abs_10 is also valid while
abs_11 and
abs_12 are both invalid.
Back to TopOther Keywords
In addition to
abstract, there are several other keywords that can be used in procedure blocks for performing specific tasks. In this section we mention a few important ones.
Back to TopSupplying predicates
The user can manually supply predicates to guide MAGIC's predicate abstraction. Often this is useful when MAGIC fails to discover a satisfactory set of predicates in a reasonable amount of time. Predicates are supplied in a per-procedure basis. An important feature of MAGIC is that all user-supplied predicates for a procedure
proc must be syntactically equivalent to some branch condition in
proc.Otherwise that predicate will be simply ignored by MAGIC. For example consider the following C procedure:
int proc(){
int x = 5; if(x < 10) return -1; else return 0;}Suppose we want to prove using MAGIC that
proc is correctly specified by the following LTS:
PROC = ( return {$0 == -1} -> STOP ).
Normally we would do this by simply asking MAGIC to perform automated abstraction refinement (using the
--optPred option). However suppose we have a good idea about which predicate MAGIC will need to complete successfully. For example, in this case
(x < 10) is the required predicate (note that this corresponds to a branch condition in
proc). Then we can simply tell MAGIC to use this predicate by using the
predicate keyword. The following procedure block shows how to do this:
cproc proc {
predicate (x < 10);
}
MAGIC will look for branch statements in
proc which have a branch condition
(x < 10). If it finds any such branch, it will use the corresponding branch condition as a
seed predicate. Otherwise it will ignore the user supplied predicate. Multiple predicates can be supplied in one statement using a comma-separated list or they can be supplied via multiple predicate statements. Also the order in which predicates are supplied is irrelevant. For example the two following procedure blocks each have the same effect as the procedure block above:
cproc proc {
predicate (y == 10) , (w == 5) , (z +w > 20) , (x < 10) , (x+y != 5);
}
cproc proc {
predicate (x+y != 5);
predicate (z+w > 20) , (y == 10);
predicate (x < 10) , (w == 5);
}
Back to TopInlining Procedures
Suppose procedure
foo calls procedure
bar. Normally MAGIC will
not inline bar within
foo even if the code for
bar is available. It has to be told explicitly to do this via the
inline keyword. Here's a procedure block that demonstrates how to do this. Once again inlining has to be done on a procedure-to-procedure basis. For example the following procedure block will not cause
bar to be inlined within some other procedure
baz.
cproc foo {
inline bar;
}
Back to TopDrawing with MAGIC
MAGIC can be used to output control flow graphs, LTSs and intermediate data structures as postscript files. This is very useful for visualization and understanding. For example, using the following command line on these
draw.pp and
draw-1.0.spec files produces this
draw-1.0.ps file.
$ magic --abstraction abs_1 draw.pp draw-1.0.spec --optPred --drawPredAbsLTS --drawFile draw-1.0.ps
Also, using the following command line on
my_proc.pp and
my_spec-1.0.spec yields this
my_proc-1.0.ps.
$ magic --abstraction abs_5 my_proc.pp my_spec-1.0.spec --optPred --drawPredAbsLTS --drawFile my_proc-1.0.psPlease look at the user's
manual for more details on command line options that control MAGIC's drawing capabilities. Also
note that
in order to draw its figures MAGIC requires the
Graphviz package, and in particular the
DOT tool. However, if you do not want to use MAGIC's drawing capabilities, there is no need to install Graphviz.
Back to TopQuestions and Comments
At this point, you should be more or less familiar with MAGIC. However I am sure there will be many questions and suggestions. Please feel free to
email me and I will do my best to respond promptly and correctly. Have fun with MAGIC !!
Back to Top