Development of Formally Verified Erlang Programs a case study Thomas Arts Clara Benac Earle Computer Science Lab Stockholm, Sweden
Research question how can we identify the hard-to-find errors in the code? can formal methods help in finding errors not uncovered by testing?
AXD 301 Architecture CP Switch Core DPDP DPDP DPDP DPDP DPDP DPDP DPDP AXD 301 Call setup
AXD 301 Architecture CP Switch Core DPDP DPDP DPDP DPDP DPDP DPDP DPDP CP OM CP OM CP OM CC CP CC OM AXD 301 fault tolerance
CP CC CP CC CP Switch Core DPDP DPDP DPDP DPDP DPDP DPDP DPDP CP OM CP OM CP OM CP CC OM CP OM CP CC CP CC node OM node app Billing application Take over
CP CC node OM node Billing application app Take over take over
CP OM node app CP CC node OM node Billing application app Take over
Application lock During take over the respective application should not be used. distributed resource locker with shared and exclusive locks
CLIENTSRESOURCES A C B LOCKER CLIENT 1 CLIENT 2 CLIENT 3 ok {request,[A],shared} ok {request,[A],exclusive} ok {release} done {release} done {request,[A,B],shared} C1 C2 C3
example -module(client). start_link(Locker) -> {ok,spawn_link(loop,[Locker])}. loop(Locker) -> gen_server:call(Locker,request), critical(), gen_server:call(Locker,release), loop(Locker).
example start_link() -> gen_server:start_link(locker,[],[]). init([]) -> {ok,[]}. handle_call(request,Client,Pending)-> case Pending of [] -> {reply, ok, [Client]}; _ -> {noreply, Pending ++ [Client]} end; handle_call(release, Client, [_|Pending]) -> case Pending of [] -> {reply, done, []}; _ -> gen_server:reply(hd(Pending), ok), {reply, done, Pending} end.
Supervisor processes standard supervision structure can be used to obtain initialization information for transition diagram supervisor locker gen_server client start supervision tree with 5 clients supervisor:start(locker_sup,start,[5]).
Testing versus Verification Thus, for one input, 100% coverage with verification testing: many program runs on different input verification: all runs on different input verify:allruns(locker_sup,start,[8]).
Mutual exclusion (at most one client has access to resource) -module(client). start_link(Locker) -> {ok,spawn_link(loop,[Locker])}. loop(Locker) -> gen_server:call(Locker,request), critical(), gen_server:call(Locker,release), loop(Locker). io:format(“enter cs~n”), critical(), io:format(“exit cs~n”), erlang:trace for gen_server:call
testing io client 2client 1 enter cs exit cs enter cs exit cs enter cs exit cs
Verification: generate State Space clients states transitions
Erlang -> transitions start verification with 2 clients verify:allruns(locker_sup,start,[2]) our Tool locker.erl client.erl locker_sup.erl client_sup.erl our Tool our Tool our Tool our Tool EtoE rest tool locker.erl client.erl init.erl instantiation
Erlang -> transitions start verification with 2 clients etomcrl:instantiator(locker_sup,start,[2]) locker.erl client.erl locker_sup.erl client_sup.erl locker.erl client.erl init.erl instantiation tomcrl.erl instantiation EtoE rest tool EtoPmcrl
Erlang -> transitions locker.erl client.erl locker_sup.erl client_sup.erl instantiation tomcrl.erl instantiation EtoE rest tool EtoPmcrl rest tool CWI tool instantiator locker.mCRL toMCRL start verification with 2 clients etomcrl:instantiator(locker_sup,start,[2]) locker.erl client.erl init.erl
Erlang -> transitions locker.erl client.erl locker_sup.erl client_sup.erl instantiation tomcrl.erl instantiation EtoE rest tool EtoPmcrl CWI tool instantiator locker.mCRL toMCRL start verification with 2 clients etomcrl:instantiator(locker_sup,start,[2]) locker.erl client.erl init.erl Aldebaran locker.aut
State Space analysis simulation with backtrack possibilities find execution sequence deadlock check states in the graph without out-arrow property check such as mutual exclusion
State Space analysis Between two handle_call(request,_,_) there should be a handle_call(release,_,_). [-*,“ handle_call(request,_,_) ”, (not “ handle_call(release,_,_) ”)*, “ handle_call(request,_,_) ” ]false Properties are specified as regular expressions over Erlang function calls in combination with [] and <> operators. After a gen_server:call(locker, request) there is always a gen_server:call(locker,release) possible. [-*,“ gen_server:call(locker, request) ”] true
Conclusions We developed software to verify properties of Erlang programs We verified a resource locker program featuring multiple resources with shared and exclusive access (upto 6 clients in many different configurations) State space upto a million states (several techniques to reduces state space if property is given) Working on addition of Erlang constructs to cover more of the language (fault tolerance handling, gen_fsm)