|
| 1 | +(** Analysis of must-received pthread_signals. *) |
| 2 | + |
| 3 | +open Prelude.Ana |
| 4 | +open Analyses |
| 5 | +module LF = LibraryFunctions |
| 6 | + |
| 7 | +module Spec : Analyses.MCPSpec = |
| 8 | +struct |
| 9 | + module Signals = SetDomain.ToppedSet (ValueDomain.Addr) (struct let topname = "All signals" end) |
| 10 | + module MustSignals = Lattice.Reverse (Signals) |
| 11 | + |
| 12 | + include Analyses.DefaultSpec |
| 13 | + module V = VarinfoV |
| 14 | + |
| 15 | + let name () = "pthreadSignals" |
| 16 | + module D = MustSignals |
| 17 | + module C = MustSignals |
| 18 | + module G = SetDomain.ToppedSet (MHP) (struct let topname = "All Threads" end) |
| 19 | + |
| 20 | + let rec conv_offset x = |
| 21 | + match x with |
| 22 | + | `NoOffset -> `NoOffset |
| 23 | + | `Index (Const (CInt (i,_,s)),o) -> `Index (IntDomain.of_const (i,Cilfacade.ptrdiff_ikind (),s), conv_offset o) |
| 24 | + | `Index (_,o) -> `Index (ValueDomain.IndexDomain.top (), conv_offset o) |
| 25 | + | `Field (f,o) -> `Field (f, conv_offset o) |
| 26 | + |
| 27 | + let eval_exp_addr (a: Queries.ask) exp = |
| 28 | + let gather_addr (v,o) b = ValueDomain.Addr.from_var_offset (v,conv_offset o) :: b in |
| 29 | + match a.f (Queries.MayPointTo exp) with |
| 30 | + | a when not (Queries.LS.is_top a) && not (Queries.LS.mem (dummyFunDec.svar,`NoOffset) a) -> |
| 31 | + Queries.LS.fold gather_addr (Queries.LS.remove (dummyFunDec.svar, `NoOffset) a) [] |
| 32 | + | _ -> [] |
| 33 | + |
| 34 | + let possible_vinfos a cv_arg = |
| 35 | + List.filter_map ValueDomain.Addr.to_var_may (eval_exp_addr a cv_arg) |
| 36 | + |
| 37 | + (* transfer functions *) |
| 38 | + let assign ctx (lval:lval) (rval:exp) : D.t = |
| 39 | + ctx.local |
| 40 | + |
| 41 | + let branch ctx (exp:exp) (tv:bool) : D.t = |
| 42 | + ctx.local |
| 43 | + |
| 44 | + let body ctx (f:fundec) : D.t = |
| 45 | + ctx.local |
| 46 | + |
| 47 | + let return ctx (exp:exp option) (f:fundec) : D.t = |
| 48 | + ctx.local |
| 49 | + |
| 50 | + let enter ctx (lval: lval option) (f:fundec) (args:exp list) : (D.t * D.t) list = |
| 51 | + [ctx.local, ctx.local] |
| 52 | + |
| 53 | + let combine ctx (lval:lval option) fexp (f:fundec) (args:exp list) fc (au:D.t) : D.t = |
| 54 | + au |
| 55 | + |
| 56 | + let special ctx (lval: lval option) (f:varinfo) (arglist:exp list) : D.t = |
| 57 | + let desc = LF.find f in |
| 58 | + match desc.special arglist with |
| 59 | + | Signal cond |
| 60 | + | Broadcast cond -> |
| 61 | + let mhp = G.singleton @@ MHP.current (Analyses.ask_of_ctx ctx) in |
| 62 | + let publish_one a = ctx.sideg a mhp in |
| 63 | + let possible_vars = possible_vinfos (Analyses.ask_of_ctx ctx) cond in |
| 64 | + List.iter publish_one possible_vars; |
| 65 | + ctx.local |
| 66 | + | Wait {cond = cond; _} -> |
| 67 | + let current_mhp = MHP.current (Analyses.ask_of_ctx ctx) in |
| 68 | + let module Signalled = struct |
| 69 | + type signalled = Never | NotConcurrently | PossiblySignalled |
| 70 | + |
| 71 | + let (|||) a b = match a,b with |
| 72 | + | PossiblySignalled, _ |
| 73 | + | _, PossiblySignalled -> PossiblySignalled |
| 74 | + | NotConcurrently , _ |
| 75 | + | _, NotConcurrently -> NotConcurrently |
| 76 | + | Never, Never -> Never |
| 77 | + |
| 78 | + let can_be_signalled a = |
| 79 | + let signalling_tids = ctx.global a in |
| 80 | + if G.is_top signalling_tids then |
| 81 | + PossiblySignalled |
| 82 | + else if G.is_empty signalling_tids then |
| 83 | + Never |
| 84 | + else if not @@ G.exists (MHP.may_happen_in_parallel current_mhp) signalling_tids then |
| 85 | + NotConcurrently |
| 86 | + else |
| 87 | + PossiblySignalled |
| 88 | + end |
| 89 | + in |
| 90 | + let open Signalled in |
| 91 | + let add_if_singleton conds = match conds with | [a] -> Signals.add (ValueDomain.Addr.from_var a) ctx.local | _ -> ctx.local in |
| 92 | + let conds = possible_vinfos (Analyses.ask_of_ctx ctx) cond in |
| 93 | + (match List.fold_left (fun acc cond -> can_be_signalled cond ||| acc) Never conds with |
| 94 | + | PossiblySignalled -> add_if_singleton conds |
| 95 | + | NotConcurrently -> |
| 96 | + (M.warn ~category:Deadcode "The condition variable(s) pointed to by %a are never signalled concurrently, succeeding code is live due to spurious wakeups only!" Basetype.CilExp.pretty cond; ctx.local) |
| 97 | + | Never -> |
| 98 | + (M.warn ~category:Deadcode "The condition variable(s) pointed to by %a are never signalled, succeeding code is live due to spurious wakeups only!" Basetype.CilExp.pretty cond; ctx.local) |
| 99 | + ) |
| 100 | + |
| 101 | + | TimedWait _ -> |
| 102 | + (* Time could simply have elapsed *) |
| 103 | + ctx.local |
| 104 | + | _ -> ctx.local |
| 105 | + |
| 106 | + let startstate v = Signals.empty () |
| 107 | + let threadenter ctx lval f args = [ctx.local] |
| 108 | + let threadspawn ctx lval f args fctx = ctx.local |
| 109 | + let exitstate v = Signals.empty () |
| 110 | +end |
| 111 | + |
| 112 | +let _ = |
| 113 | + MCP.register_analysis ~dep:["mutex"] (module Spec : MCPSpec) |
0 commit comments