From 8fff9a5d9b8c89f2e8d1a0a294a8e0ea64edb86b Mon Sep 17 00:00:00 2001 From: Michael Schwarz Date: Fri, 24 Jan 2025 17:43:27 +0100 Subject: [PATCH] Onces --- src/analyses/pthreadOnce.ml | 90 ++++++++++++++++++++++++++++ src/framework/constraints.ml | 9 ++- tests/regression/83-once/01-sanity.c | 2 +- 3 files changed, 99 insertions(+), 2 deletions(-) create mode 100644 src/analyses/pthreadOnce.ml diff --git a/src/analyses/pthreadOnce.ml b/src/analyses/pthreadOnce.ml new file mode 100644 index 0000000000..30c7756089 --- /dev/null +++ b/src/analyses/pthreadOnce.ml @@ -0,0 +1,90 @@ +(** Must active and have passed pthreadOnce calls ([pthreadOnce]). *) + +open GoblintCil +open Analyses +module LF = LibraryFunctions + +module Spec = +struct + module Onces = struct + include SetDomain.ToppedSet (CilType.Varinfo) (struct let topname = "All onces" end) + let name () = "mayOnces" + end + + module ActiveOnces = struct + include Lattice.Reverse (Onces) + let name () = "active" + end + + module SeenOnces = struct + include Lattice.Reverse (Onces) + let name () = "seen" + end + + include Analyses.DefaultSpec + + let name () = "pthreadOnce" + module D = Lattice.Prod (ActiveOnces) (SeenOnces) + include Analyses.ValueContexts(D) + + (* transfer functions *) + let assign man (lval:lval) (rval:exp) : D.t = + man.local + + let branch man (exp:exp) (tv:bool) : D.t = + man.local + + let body man (f:fundec) : D.t = + man.local + + let return man (exp:exp option) (f:fundec) : D.t = + man.local + + let enter man (lval: lval option) (f:fundec) (args:exp list) : (D.t * D.t) list = + [man.local, man.local] + + let combine_env man lval fexp f args fc au f_ask = + au + + let combine_assign man (lval:lval option) fexp (f:fundec) (args:exp list) fc (au:D.t) (f_ask: Queries.ask) : D.t = + man.local + + let special man (lval: lval option) (f:varinfo) (arglist:exp list) : D.t = + man.local + + let startstate v = (Onces.empty (), Onces.empty ()) + + let possible_vinfos (a: Queries.ask) barrier = + Queries.AD.to_var_may (a.f (Queries.MayPointTo barrier)) + + let event man (e: Events.t) oman : D.t = + match e with + | Events.EnterOnce { once_control; tf } -> + (let (active, seen) = man.local in + let ask = Analyses.ask_of_man man in + match possible_vinfos ask once_control with + | [v] -> + (Onces.add v active, seen) + | _ -> + man.local) + | Events.LeaveOnce { once_control } -> + (let (active, seen) = man.local in + let ask = Analyses.ask_of_man man in + let active' = Onces.diff active (Onces.of_list (possible_vinfos ask once_control)) in + let seen' = match possible_vinfos ask once_control with + | [v] -> Onces.add v seen + | _ -> seen + in + (active', seen')) + | _ -> man.local + + let threadenter man ~multiple lval f args = + let (_, seen) = man.local in + [Onces.empty (), seen] + + let threadspawn man ~multiple lval f args fman = man.local + let exitstate v = D.top () +end + +let _ = + MCP.register_analysis (module Spec : MCPSpec) diff --git a/src/framework/constraints.ml b/src/framework/constraints.ml index d2c1c8215b..97dffe5d6c 100644 --- a/src/framework/constraints.ml +++ b/src/framework/constraints.ml @@ -271,7 +271,14 @@ struct S.event proc_man (Events.LeaveOnce { once_control }) proc_man in let not_enter = - S.event man (Events.EnterOnce { once_control; tf = false }) man + let d' = S.event man (Events.EnterOnce { once_control; tf = false }) man in + let rec d'_man = + { man with + ask = (fun (type a) (q: a Queries.t) -> S.query d'_man q); + local = d'; + } + in + S.event d'_man (Events.LeaveOnce { once_control }) d'_man in D.join enter not_enter in diff --git a/tests/regression/83-once/01-sanity.c b/tests/regression/83-once/01-sanity.c index 954f70dd4b..3d7875e0c5 100644 --- a/tests/regression/83-once/01-sanity.c +++ b/tests/regression/83-once/01-sanity.c @@ -1,4 +1,4 @@ -// PARAM: --set pre.cppflags[+] "-DGOBLINT_NO_PTHREAD_ONCE" +// PARAM: --set pre.cppflags[+] "-DGOBLINT_NO_PTHREAD_ONCE" --set ana.activated[+] pthreadOnce #include #include