Skip to content

Commit 1fed2e7

Browse files
committed
Use variant type for kind of protection instead of bool
1 parent 4aa0ad2 commit 1fed2e7

File tree

4 files changed

+68
-56
lines changed

4 files changed

+68
-56
lines changed

src/analyses/basePriv.ml

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -370,7 +370,7 @@ struct
370370
if atomic || ask.f (GhostVarAvailable (Locked m')) then (
371371
let cpa = get_m_with_mutex_inits ask getg m' in (* Could be more precise if mutex_inits invariant is added by disjunction instead of joining abstract values. *)
372372
let inv = CPA.fold (fun v _ acc ->
373-
if ask.f (MustBeProtectedBy {mutex = m'; global = v; write = true; protection = Strong}) then
373+
if ask.f (MustBeProtectedBy {mutex = m'; global = v; kind = Write; protection = Strong}) then
374374
let inv = ValueDomain.invariant_global (fun g -> CPA.find g cpa) v in
375375
Invariant.(acc && inv)
376376
else
@@ -706,7 +706,7 @@ struct
706706

707707
let threadspawn (ask:Queries.ask) get set (st: BaseComponents (D).t) =
708708
let is_recovered_st = ask.f (Queries.MustBeSingleThreaded {since_start = false}) && not @@ ask.f (Queries.MustBeSingleThreaded {since_start = true}) in
709-
let unprotected_after x = ask.f (Q.MayBePublic {global=x; write=true; protection=Weak}) in
709+
let unprotected_after x = ask.f (Q.MayBePublic {global=x; kind=Write; protection=Weak}) in
710710
if is_recovered_st then
711711
(* Remove all things that are now unprotected *)
712712
let cpa' = CPA.fold (fun x v cpa ->
@@ -750,14 +750,14 @@ struct
750750
let startstate () = ()
751751

752752
let read_global (ask: Queries.ask) getg (st: BaseComponents (D).t) x =
753-
if is_unprotected ask ~write:false x then
753+
if is_unprotected ask ~kind:ReadWrite x then
754754
VD.join (CPA.find x st.cpa) (getg x)
755755
else
756756
CPA.find x st.cpa
757757

758758
let write_global ?(invariant=false) (ask: Queries.ask) getg sideg (st: BaseComponents (D).t) x v =
759759
if not invariant then (
760-
if is_unprotected ask ~write:false x then
760+
if is_unprotected ask ~kind:ReadWrite x then
761761
sideg x v;
762762
if !earlyglobs then (* earlyglobs workaround for 13/60 *)
763763
sideg x v (* TODO: is this needed for anything? 13/60 doesn't work for other reasons *)
@@ -766,7 +766,7 @@ struct
766766

767767
let lock ask getg (st: BaseComponents (D).t) m =
768768
let cpa' = CPA.mapi (fun x v ->
769-
if is_protected_by ask ~write:false m x && is_unprotected ask ~write:false x then (* is_in_Gm *)
769+
if is_protected_by ask ~kind:ReadWrite m x && is_unprotected ask ~kind:ReadWrite x then (* is_in_Gm *)
770770
VD.join (CPA.find x st.cpa) (getg x)
771771
else
772772
v
@@ -776,8 +776,8 @@ struct
776776

777777
let unlock ask getg sideg (st: BaseComponents (D).t) m =
778778
CPA.iter (fun x v ->
779-
if is_protected_by ask ~write:false m x then ( (* is_in_Gm *)
780-
if is_unprotected_without ask ~write:false x m then (* is_in_V' *)
779+
if is_protected_by ask ~kind:ReadWrite m x then ( (* is_in_Gm *)
780+
if is_unprotected_without ask ~kind:ReadWrite x m then (* is_in_V' *)
781781
sideg x v
782782
)
783783
) st.cpa;
@@ -787,7 +787,7 @@ struct
787787
let branched_sync () =
788788
(* required for branched thread creation *)
789789
CPA.iter (fun x v ->
790-
if is_global ask x && is_unprotected ask ~write:false x then
790+
if is_global ask x && is_unprotected ask ~kind:ReadWrite x then
791791
sideg x v
792792
) st.cpa;
793793
st
@@ -832,7 +832,7 @@ struct
832832
| _ -> ()
833833

834834
let invariant_global (ask: Q.ask) getg g =
835-
let locks = ask.f (Q.MustProtectingLocks {global = g; write = false}) in
835+
let locks = ask.f (Q.MustProtectingLocks {global = g; kind = ReadWrite}) in
836836
if LockDomain.MustLockset.is_all locks then
837837
Invariant.none
838838
else (
@@ -988,7 +988,7 @@ struct
988988
(* Extra precision in implementation to pass tests:
989989
If global is read-protected by multiple locks,
990990
then inner unlock shouldn't yet publish. *)
991-
if not Param.check_read_unprotected || is_unprotected_without ask ~write:false x m then
991+
if not Param.check_read_unprotected || is_unprotected_without ask ~kind:ReadWrite x m then
992992
sideg (V.protected x) v;
993993
if atomic then
994994
sideg (V.unprotected x) v; (* Publish delayed unprotected write as if it were protected by the atomic section. *)
@@ -1076,7 +1076,7 @@ struct
10761076
| `Left g' -> (* unprotected *)
10771077
ValueDomain.invariant_global (fun g -> getg (V.unprotected g)) g'
10781078
| `Right g' -> (* protected *)
1079-
let locks = ask.f (Q.MustProtectingLocks {global = g'; write = true}) in
1079+
let locks = ask.f (Q.MustProtectingLocks {global = g'; kind = Write}) in
10801080
if LockDomain.MustLockset.is_all locks || LockDomain.MustLockset.is_empty locks then
10811081
Invariant.none
10821082
else if VD.equal (getg (V.protected g')) (getg (V.unprotected g')) then

src/analyses/commonPriv.ml

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -82,26 +82,28 @@ end
8282
module Protection =
8383
struct
8484
open Q.Protection
85-
let is_unprotected ask ?(write=true) ?(protection=Strong) x: bool =
85+
open Q.ProtectionKind
86+
87+
let is_unprotected ask ?(kind=Write) ?(protection=Strong) x: bool =
8688
let multi = if protection = Weak then ThreadFlag.is_currently_multi ask else ThreadFlag.has_ever_been_multi ask in
8789
(!GobConfig.earlyglobs && not multi && not (is_excluded_from_earlyglobs x)) ||
8890
(
8991
multi &&
90-
ask.f (Q.MayBePublic {global=x; write; protection})
92+
ask.f (Q.MayBePublic {global=x; kind; protection})
9193
)
9294

93-
let is_unprotected_without ask ?(write=true) ?(protection=Strong) x m: bool =
95+
let is_unprotected_without ask ?(kind=Write) ?(protection=Strong) x m: bool =
9496
(if protection = Weak then ThreadFlag.is_currently_multi ask else ThreadFlag.has_ever_been_multi ask) &&
95-
ask.f (Q.MayBePublicWithout {global=x; write; without_mutex=m; protection})
97+
ask.f (Q.MayBePublicWithout {global=x; kind; without_mutex=m; protection})
9698

97-
let is_protected_by ask ?(write=true) ?(protection=Strong) m x: bool =
99+
let is_protected_by ask ?(kind=Write) ?(protection=Strong) m x: bool =
98100
is_global ask x &&
99101
not (VD.is_immediate_type x.vtype) &&
100-
ask.f (Q.MustBeProtectedBy {mutex=m; global=x; write; protection})
102+
ask.f (Q.MustBeProtectedBy {mutex=m; global=x; kind; protection})
101103

102104
let protected_vars (ask: Q.ask): varinfo list =
103105
LockDomain.MustLockset.fold (fun ml acc ->
104-
Q.VS.join (ask.f (Q.MustProtectedVars {mutex = ml; write = true})) acc
106+
Q.VS.join (ask.f (Q.MustProtectedVars {mutex = ml; kind = Write})) acc
105107
) (ask.f Q.MustLockset) (Q.VS.empty ())
106108
|> Q.VS.elements
107109
end

src/analyses/mutexAnalysis.ml

Lines changed: 38 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -59,25 +59,31 @@ struct
5959

6060
let name () = "strong protection * weak protection"
6161

62-
let get ~write protection (s,w) =
62+
let get ~kind protection (s,w) =
6363
let (rw, w) = match protection with
6464
| Queries.Protection.Strong -> s
6565
| Weak -> w
6666
in
67-
if write then w else rw
67+
match kind with
68+
| Queries.ProtectionKind.Write -> w
69+
| ReadWrite -> rw
6870
end
6971

7072
(** Collects information about which variables are protected by which mutexes *)
7173
module GProtecting: sig
7274
include Lattice.S
73-
val make: write:bool -> recovered:bool -> MustLockset.t -> t
74-
val get: write:bool -> Queries.Protection.t -> t -> MustLockset.t
75+
val make: kind:Queries.ProtectionKind.t -> recovered:bool -> MustLockset.t -> t
76+
val get: kind:Queries.ProtectionKind.t -> Queries.Protection.t -> t -> MustLockset.t
7577
end = struct
7678
include MakeP (MustLockset)
7779

78-
let make ~write ~recovered locks =
80+
let make ~kind ~recovered locks =
7981
(* If the access is not a write, set to T so intersection with current write-protecting is identity *)
80-
let wlocks = if write then locks else MustLockset.all () in
82+
let wlocks =
83+
match kind with
84+
| Queries.ProtectionKind.Write -> locks
85+
| ReadWrite -> MustLockset.all ()
86+
in
8187
if recovered then
8288
(* If we are in single-threaded mode again, this does not need to be added to set of mutexes protecting in mt-mode only *)
8389
((locks, wlocks), (MustLockset.all (), MustLockset.all ()))
@@ -89,17 +95,16 @@ struct
8995
(** Collects information about which mutex protects which variable *)
9096
module GProtected: sig
9197
include Lattice.S
92-
val make: write:bool -> VarSet.t -> t
93-
val get: write:bool -> Queries.Protection.t -> t -> VarSet.t
98+
val make: kind:Queries.ProtectionKind.t -> VarSet.t -> t
99+
val get: kind:Queries.ProtectionKind.t -> Queries.Protection.t -> t -> VarSet.t
94100
end = struct
95101
include MakeP (VarSet)
96102

97-
let make ~write vs =
103+
let make ~kind vs =
98104
let vs_empty = VarSet.empty () in
99-
if write then
100-
((vs_empty, vs), (vs_empty, vs))
101-
else
102-
((vs, vs_empty), (vs, vs_empty))
105+
match kind with
106+
| Queries.ProtectionKind.Write -> ((vs_empty, vs), (vs_empty, vs))
107+
| ReadWrite -> ((vs, vs_empty), (vs, vs_empty))
103108
end
104109

105110
module G =
@@ -198,43 +203,43 @@ struct
198203
let query (man: (D.t, _, _, V.t) man) (type a) (q: a Queries.t): a Queries.result =
199204
let ls, m = man.local in
200205
(* get the set of mutexes protecting the variable v in the given mode *)
201-
let protecting ~write mode v = GProtecting.get ~write mode (G.protecting (man.global (V.protecting v))) in
206+
let protecting ~kind mode v = GProtecting.get ~kind mode (G.protecting (man.global (V.protecting v))) in
202207
match q with
203208
| Queries.MayBePublic _ when MustLocksetRW.is_all ls -> false
204-
| Queries.MayBePublic {global=v; write; protection} ->
209+
| Queries.MayBePublic {global=v; kind; protection} ->
205210
let held_locks = MustLocksetRW.to_must_lockset (MustLocksetRW.filter snd ls) in
206-
let protecting = protecting ~write protection v in
211+
let protecting = protecting ~kind protection v in
207212
(* TODO: unsound in 29/24, why did we do this before? *)
208213
(* if Mutexes.mem verifier_atomic (Lockset.export_locks man.local) then
209214
false
210215
else *)
211216
MustLockset.disjoint held_locks protecting
212217
| Queries.MayBePublicWithout _ when MustLocksetRW.is_all ls -> false
213-
| Queries.MayBePublicWithout {global=v; write; without_mutex; protection} ->
218+
| Queries.MayBePublicWithout {global=v; kind; without_mutex; protection} ->
214219
let held_locks = MustLockset.remove without_mutex (MustLocksetRW.to_must_lockset ls) in
215-
let protecting = protecting ~write protection v in
220+
let protecting = protecting ~kind protection v in
216221
(* TODO: unsound in 29/24, why did we do this before? *)
217222
(* if Mutexes.mem verifier_atomic (Lockset.export_locks (Lockset.remove (without_mutex, true) man.local)) then
218223
false
219224
else *)
220225
MustLockset.disjoint held_locks protecting
221-
| Queries.MustBeProtectedBy {mutex = ml; global=v; write; protection} ->
222-
let protecting = protecting ~write protection v in
226+
| Queries.MustBeProtectedBy {mutex = ml; global=v; kind; protection} ->
227+
let protecting = protecting ~kind protection v in
223228
(* TODO: unsound in 29/24, why did we do this before? *)
224229
(* if LockDomain.Addr.equal mutex (LockDomain.Addr.of_var LF.verifier_atomic_var) then
225230
true
226231
else *)
227232
MustLockset.mem ml protecting
228-
| Queries.MustProtectingLocks {global; write} ->
229-
protecting ~write Strong global
233+
| Queries.MustProtectingLocks {global; kind} ->
234+
protecting ~kind Strong global
230235
| Queries.MustLockset ->
231236
let held_locks = MustLocksetRW.to_must_lockset (MustLocksetRW.filter snd ls) in
232237
held_locks
233238
| Queries.MustBeAtomic ->
234239
let held_locks = MustLocksetRW.to_must_lockset (MustLocksetRW.filter snd ls) in
235240
MustLockset.mem (LF.verifier_atomic_var, `NoOffset) held_locks (* TODO: Mval.of_var *)
236-
| Queries.MustProtectedVars {mutex; write} ->
237-
let protected = GProtected.get ~write Strong (G.protected (man.global (V.protected mutex))) in
241+
| Queries.MustProtectedVars {mutex; kind} ->
242+
let protected = GProtected.get ~kind Strong (G.protected (man.global (V.protected mutex))) in
238243
VarSet.fold (fun v acc ->
239244
Queries.VS.add v acc
240245
) protected (Queries.VS.empty ())
@@ -245,13 +250,13 @@ struct
245250
begin match g with
246251
| `Left g' -> (* protecting *)
247252
if GobConfig.get_bool "dbg.print_protection" then (
248-
let protecting = GProtecting.get ~write:false Strong (G.protecting (man.global g)) in (* readwrite protecting *)
253+
let protecting = GProtecting.get ~kind:ReadWrite Strong (G.protecting (man.global g)) in (* readwrite protecting *)
249254
let s = MustLockset.cardinal protecting in
250255
M.info_noloc ~category:Race "Variable %a read-write protected by %d mutex(es): %a" CilType.Varinfo.pretty g' s MustLockset.pretty protecting
251256
)
252257
| `Right m -> (* protected *)
253258
if GobConfig.get_bool "dbg.print_protection" then (
254-
let protected = GProtected.get ~write:false Strong (G.protected (man.global g)) in (* readwrite protected *)
259+
let protected = GProtected.get ~kind:ReadWrite Strong (G.protected (man.global g)) in (* readwrite protected *)
255260
let s = VarSet.cardinal protected in
256261
max_protected := max !max_protected s;
257262
sum_protected := !sum_protected + s;
@@ -293,21 +298,21 @@ struct
293298
| Some v ->
294299
if not (MustLocksetRW.is_all (fst oman.local)) then
295300
let locks = MustLocksetRW.to_must_lockset (MustLocksetRW.filter snd (fst oman.local)) in
296-
let write = match kind with
297-
| Write | Free -> true
298-
| Read -> false
301+
let kind = match kind with
302+
| Write | Free -> Queries.ProtectionKind.Write
303+
| Read -> ReadWrite
299304
| Call
300-
| Spawn -> false (* TODO: nonsense? *)
305+
| Spawn -> ReadWrite (* TODO: nonsense? *)
301306
in
302-
let s = GProtecting.make ~write ~recovered:is_recovered_to_st locks in
307+
let s = GProtecting.make ~kind ~recovered:is_recovered_to_st locks in
303308
man.sideg (V.protecting v) (G.create_protecting s);
304309

305310
if !AnalysisState.postsolving then (
306-
let protecting mode = GProtecting.get ~write mode (G.protecting (man.global (V.protecting v))) in
311+
let protecting mode = GProtecting.get ~kind mode (G.protecting (man.global (V.protecting v))) in
307312
let held_strong = protecting Strong in
308313
let held_weak = protecting Weak in
309314
let vs = VarSet.singleton v in
310-
let protected = G.create_protected @@ GProtected.make ~write vs in
315+
let protected = G.create_protected @@ GProtected.make ~kind vs in
311316
MustLockset.iter (fun ml -> man.sideg (V.protected ml) protected) held_strong;
312317
(* If the mutex set here is top, it is actually not accessed *)
313318
if is_recovered_to_st && not @@ MustLockset.is_all held_weak then

src/domains/queries.ml

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,11 @@ module MustBool = BoolDomain.MustBool
3939

4040
module Unit = Lattice.Unit
4141

42+
module ProtectionKind =
43+
struct
44+
type t = ReadWrite | Write [@@deriving ord, hash]
45+
end
46+
4247
(** Different notions of protection for a global variables g by a mutex m
4348
m protects g strongly if:
4449
- whenever g is accessed after the program went multi-threaded for the first time, m is held
@@ -55,11 +60,11 @@ module AllocationLocation = struct
5560
end
5661

5762
(* Helper definitions for deriving complex parts of Any.compare below. *)
58-
type maybepublic = {global: CilType.Varinfo.t; write: bool; protection: Protection.t} [@@deriving ord, hash]
59-
type maybepublicwithout = {global: CilType.Varinfo.t; write: bool; without_mutex: LockDomain.MustLock.t; protection: Protection.t} [@@deriving ord, hash]
60-
type mustbeprotectedby = {mutex: LockDomain.MustLock.t; global: CilType.Varinfo.t; write: bool; protection: Protection.t} [@@deriving ord, hash]
61-
type mustprotectedvars = {mutex: LockDomain.MustLock.t; write: bool} [@@deriving ord, hash]
62-
type mustprotectinglocks = {global: CilType.Varinfo.t; write: bool} [@@deriving ord, hash]
63+
type maybepublic = {global: CilType.Varinfo.t; kind: ProtectionKind.t; protection: Protection.t} [@@deriving ord, hash]
64+
type maybepublicwithout = {global: CilType.Varinfo.t; kind: ProtectionKind.t; without_mutex: LockDomain.MustLock.t; protection: Protection.t} [@@deriving ord, hash]
65+
type mustbeprotectedby = {mutex: LockDomain.MustLock.t; global: CilType.Varinfo.t; kind: ProtectionKind.t; protection: Protection.t} [@@deriving ord, hash]
66+
type mustprotectedvars = {mutex: LockDomain.MustLock.t; kind: ProtectionKind.t} [@@deriving ord, hash]
67+
type mustprotectinglocks = {global: CilType.Varinfo.t; kind: ProtectionKind.t} [@@deriving ord, hash]
6368
type access =
6469
| Memory of {exp: CilType.Exp.t; var_opt: CilType.Varinfo.t option; kind: AccessKind.t} (** Memory location access (race). *)
6570
| Point (** Program point and state access (MHP), independent of memory location. *)

0 commit comments

Comments
 (0)