|
| 1 | +(** An analysis tracking the type of a mutex. *) |
| 2 | + |
| 3 | +open GoblintCil |
| 4 | +open Analyses |
| 5 | + |
| 6 | +module MAttr = ValueDomain.MutexAttr |
| 7 | +module LF = LibraryFunctions |
| 8 | + |
| 9 | +module Spec : Analyses.MCPSpec with module D = Lattice.Unit and module C = Lattice.Unit = |
| 10 | +struct |
| 11 | + include Analyses.IdentitySpec |
| 12 | + |
| 13 | + let name () = "pthreadMutexType" |
| 14 | + module D = Lattice.Unit |
| 15 | + module C = Lattice.Unit |
| 16 | + |
| 17 | + (* Removing indexes here avoids complicated lookups and allows to have the LVals as vars here, at the price that different types of mutexes in arrays are not dinstinguished *) |
| 18 | + module O = Lval.OffsetNoIdx |
| 19 | + |
| 20 | + module V = struct |
| 21 | + include Printable.Prod(CilType.Varinfo)(O) |
| 22 | + let is_write_only _ = false |
| 23 | + end |
| 24 | + |
| 25 | + module G = MAttr |
| 26 | + |
| 27 | + (* transfer functions *) |
| 28 | + let assign ctx (lval:lval) (rval:exp) : D.t = |
| 29 | + match lval with |
| 30 | + | (Var v, o) -> |
| 31 | + (* There's no way to use the PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP etc for accesses via pointers *) |
| 32 | + let rec helper o t = function |
| 33 | + | Field ({fname = "__data"; _}, Field ({fname = "__kind"; _}, NoOffset)) when ValueDomain.Compound.is_mutex_type t -> |
| 34 | + let kind = |
| 35 | + (match Cil.constFold true rval with |
| 36 | + | Const (CInt (c, _, _)) -> MAttr.of_int c |
| 37 | + | _ -> `Top) |
| 38 | + in |
| 39 | + ctx.sideg (v,o) kind; |
| 40 | + ctx.local |
| 41 | + | Index (i,o') -> |
| 42 | + let o'' = O.of_offs (`Index (i, `NoOffset)) in |
| 43 | + helper (O.add_offset o o'') (Cilfacade.typeOffset t (Index (i,NoOffset))) o' |
| 44 | + | Field (f,o') -> |
| 45 | + let o'' = O.of_offs (`Field (f, `NoOffset)) in |
| 46 | + helper (O.add_offset o o'') (Cilfacade.typeOffset t (Field (f,NoOffset))) o' |
| 47 | + | NoOffset -> ctx.local |
| 48 | + in |
| 49 | + helper `NoOffset v.vtype o |
| 50 | + | _ -> ctx.local |
| 51 | + |
| 52 | + let special ctx (lval: lval option) (f:varinfo) (arglist:exp list) : D.t = |
| 53 | + let desc = LF.find f in |
| 54 | + match desc.special arglist with |
| 55 | + | MutexInit {mutex = mutex; attr = attr} -> |
| 56 | + let attr = ctx.ask (Queries.EvalMutexAttr attr) in |
| 57 | + let mutexes = ctx.ask (Queries.MayPointTo mutex) in |
| 58 | + (* It is correct to iter over these sets here, as mutexes need to be intialized before being used, and an analysis that detects usage before initialization is a different analysis. *) |
| 59 | + Queries.LS.iter (function (v, o) -> ctx.sideg (v,O.of_offs o) attr) mutexes; |
| 60 | + ctx.local |
| 61 | + | _ -> ctx.local |
| 62 | + |
| 63 | + let startstate v = D.bot () |
| 64 | + let threadenter ctx lval f args = [D.top ()] |
| 65 | + let threadspawn ctx lval f args fctx = ctx.local |
| 66 | + let exitstate v = D.top () |
| 67 | + |
| 68 | + let query ctx (type a) (q: a Queries.t): a Queries.result = |
| 69 | + match q with |
| 70 | + | Queries.MutexType (v,o) -> (ctx.global (v,o):MutexAttrDomain.t) |
| 71 | + | _ -> Queries.Result.top q |
| 72 | +end |
| 73 | + |
| 74 | +let _ = |
| 75 | + MCP.register_analysis (module Spec : MCPSpec) |
0 commit comments