450 likes | 569 Views
Detection of Asynchronous Message Passing Errors Using Static Analysis. Maria Christakis National Technical University of Athens, Greece Joint work with Kostis Sagonas. Concurrency. Interprocess communication. Synchronized shared structures Synchronous message passing on typed channels
E N D
Detection of Asynchronous Message Passing Errors Using Static Analysis Maria Christakis National Technical University of Athens, Greece Joint work with Kostis Sagonas
Interprocess communication • Synchronized shared structures • Synchronous message passing on typed channels • Asynchronous message passing
Erlang • Strict, dynamically typed, functional Concurrency model: • User-level processes • Asynchronous message passing
Postman • Erlang VM
House • Process
Address • Process identifier
Mailbox • Process mailbox
Mail • Any valid Erlang term
Building a house Pid = spawn(Fun)
Sending mail Pid ! Msg
Receiving mail receive p1 -> e1; … pn -> en end
Receiving mail msg1 receive p1 -> e1; … pn -> en end msg2 msg3
Receive with no messages • Possible deadlock
Receive of the wrong kind • Mailbox overflow
Receive with unneeded patterns • Unreachable code or serious functionality issue
Send nowhere received • Mailbox overflow
Message passing example -export([hello_world/0]). hello_world() -> Self = self(), Fun = fun() -> world(Self) end, Pid = spawn(Fun), register(world, Pid), world ! hello. world(Parent) -> receive hello -> Parent ! hi end.
DIscrepancy AnaLYZer for ERlang • Static analysis tool for finding discrepancies • Type errors • Exception-raising code • Unsatisfiable conditions • Redundancies • Race conditions • Why Dialyzer?
The analysis: pros • Sound for defect detection
The analysis: pros • Automatic
The analysis: pros • Fast and scalable
The analysis: cons • Sound for defect detection
1. Information • CFGs • Escape analysis • Inter-modular call graph • Sharing/alias analysis • Type information
1. Information -export([hello_world/0]). hello_world() -> Self = self(), Fun = fun() -> world(Self) end, Pid = spawn(Fun), register(world, Pid), world ! hello. world(Parent) -> receive hello -> Parent ! hi end. • Call graph
2. Communication graph -export([hello_world/0]). hello_world() -> Self = self(), Fun = fun() -> world(Self) end, Pid = spawn(Fun), register(world, Pid), world ! hello. world(Parent) -> receive hello -> Parent ! hi end.
3. Errors -export([hello_world/0]). hello_world() -> Self = self(), Fun = fun() -> world(Self) end, Pid = spawn(Fun), register(world, Pid), world ! hello. world(Parent) -> receive hello -> Parent ! hi end. The message will never be received
3. Errors • receive blah • receive No messages are sent to the process
3. Errors • 43 receive {A, 42} when is_atom(A) -> ok; foo -> … end • Infimum: {gazonk, 42} The pattern will never match messages sent to the process
Optimizations • Control-flow graph minimization • Avoiding repeated traversals • Avoiding redundant traversals
False alarm avoidance • BIFs • Sharing/alias analysis
False negatives -export([hello_world/0]). hello_world() -> Self = self(), Fun = fun() -> world(Self) end, Pid = spawn(Fun), register(world, Pid), world ! hello. world(Parent) -> receive hello -> Parent ! hi, world(Parent) end.