Skip to content

Commit f2500d5

Browse files
authored
Merge pull request #1483 from RonaldJudin/delay-widening
Implement delayed widening
2 parents 5aeb549 + bf8f4e9 commit f2500d5

16 files changed

+305
-0
lines changed

src/config/options.schema.json

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1182,6 +1182,25 @@
11821182
"description": "Delay widenings using widening tokens.",
11831183
"type": "boolean",
11841184
"default": false
1185+
},
1186+
"delay": {
1187+
"title": "ana.widen.delay",
1188+
"type": "object",
1189+
"properties": {
1190+
"local": {
1191+
"title": "ana.widen.delay.local",
1192+
"description": "Delay local constraint unknown widenings by count.",
1193+
"type": "integer",
1194+
"default": 0
1195+
},
1196+
"global": {
1197+
"title": "ana.widen.delay.global",
1198+
"description": "Delay global constraint unknown widenings by count.",
1199+
"type": "integer",
1200+
"default": 0
1201+
}
1202+
},
1203+
"additionalProperties": false
11851204
}
11861205
},
11871206
"additionalProperties": false

src/framework/control.ml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ let spec_module: (module Spec) Lazy.t = lazy (
2626
(module MCP.MCP2 : Spec)
2727
|> lift (get_int "ana.context.gas_value" >= 0) (ContextGasLifter.get_gas_lifter ())
2828
|> lift true (module WidenContextLifterSide) (* option checked in functor *)
29+
|> lift (get_int "ana.widen.delay.local" > 0) (module WideningDelay.DLifter)
2930
(* hashcons before witness to reduce duplicates, because witness re-uses contexts in domain and requires tag for PathSensitive3 *)
3031
|> lift (get_bool "ana.opt.hashcons" || arg_enabled) (module HashconsContextLifter)
3132
|> lift (get_bool "ana.opt.hashcached") (module HashCachedContextLifter)
@@ -43,6 +44,7 @@ let spec_module: (module Spec) Lazy.t = lazy (
4344
|> lift (get_bool "ana.widen.tokens") (module WideningTokenLifter.Lifter)
4445
|> lift true (module LongjmpLifter.Lifter)
4546
|> lift termination_enabled (module RecursionTermLifter.Lifter) (* Always activate the recursion termination analysis, when the loop termination analysis is activated*)
47+
|> lift (get_int "ana.widen.delay.global" > 0) (module WideningDelay.GLifter)
4648
)
4749
in
4850
GobConfig.building_spec := false;

src/goblint_lib.ml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,7 @@ module SpecLifters = SpecLifters
184184
module LongjmpLifter = LongjmpLifter
185185
module RecursionTermLifter = RecursionTermLifter
186186
module ContextGasLifter = ContextGasLifter
187+
module WideningDelay = WideningDelay
187188
module WideningToken = WideningToken
188189
module WideningTokenLifter = WideningTokenLifter
189190

src/lifters/wideningDelay.ml

Lines changed: 185 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,185 @@
1+
(** Standard widening delay with counters.
2+
3+
Abstract elements are paired with an integer counter, indicating how many times it has been widened.
4+
Lifted abstract elements are only widened if the counter exceeds a predefined limit. *)
5+
6+
open Batteries
7+
open Lattice
8+
open Analyses
9+
10+
module LocalChainParams: Printable.ChainParams =
11+
struct
12+
let n () = GobConfig.get_int "ana.widen.delay.local"
13+
let names = string_of_int
14+
end
15+
16+
module GlobalChainParams: Printable.ChainParams =
17+
struct
18+
let n () = GobConfig.get_int "ana.widen.delay.global"
19+
let names = string_of_int
20+
end
21+
22+
module Dom (Base: S) (ChainParams: Printable.ChainParams) =
23+
struct
24+
module Chain = Printable.Chain (ChainParams)
25+
include Printable.Prod (Base) (Chain)
26+
27+
let bot () = (Base.bot (), 0)
28+
let is_bot (b, _) = Base.is_bot b
29+
let top () = (Base.top (), ChainParams.n ())
30+
let is_top (b, _) = Base.is_top b
31+
32+
let leq (b1, _) (b2, _) = Base.leq b1 b2
33+
34+
(** All operations keep maximal counter. *)
35+
let join (b1, i1) (b2, i2) = (Base.join b1 b2, max i1 i2)
36+
let meet (b1, i1) (b2, i2) = (Base.meet b1 b2, max i1 i2)
37+
let widen (b1, i1) (b2, i2) =
38+
let i' = max i1 i2 in
39+
if i' < ChainParams.n () then
40+
(Base.join b1 b2, i' + 1)
41+
else
42+
(Base.widen b1 b2, i') (* Don't increase beyond n, otherwise TD3 will not reach fixpoint w.r.t. equal. *)
43+
let narrow (b1, i1) (b2, i2) = (Base.narrow b1 b2, max i1 i2)
44+
45+
let pretty_diff () ((b1, _), (b2, _)) =
46+
Base.pretty_diff () (b1, b2) (* Counters cannot violate leq. *)
47+
end
48+
49+
50+
(** Lift {!S} to use widening delay for local states.
51+
52+
All transfer functions reset the counter to 0, so counting only happens between old and new values at a local unknown. *)
53+
module DLifter (S: Spec): Spec =
54+
struct
55+
module D =
56+
struct
57+
include Dom (S.D) (LocalChainParams)
58+
59+
let printXml f (b, i) =
60+
BatPrintf.fprintf f "%a<analysis name=\"widen-delay\">%a</analysis>" S.D.printXml b Chain.printXml i
61+
end
62+
module G = S.G
63+
module C = S.C
64+
module V = S.V
65+
module P =
66+
struct
67+
include S.P
68+
let of_elt (x, _) = of_elt x
69+
end
70+
71+
let name () = S.name () ^ " with widening delay"
72+
73+
type marshal = S.marshal
74+
let init = S.init
75+
let finalize = S.finalize
76+
77+
let startstate v = (S.startstate v, 0)
78+
let exitstate v = (S.exitstate v, 0)
79+
let morphstate v (d, l) = (S.morphstate v d, l)
80+
81+
let conv (man: (D.t, G.t, C.t, V.t) man): (S.D.t, S.G.t, S.C.t, S.V.t) man =
82+
{ man with local = fst man.local
83+
; split = (fun d es -> man.split (d, 0) es)
84+
}
85+
86+
let context man fd (d, _) = S.context (conv man) fd d
87+
let startcontext () = S.startcontext ()
88+
89+
let lift_fun man f g h =
90+
f @@ h (g (conv man))
91+
92+
let lift d = (d, 0)
93+
94+
let sync man reason = lift_fun man lift S.sync ((|>) reason)
95+
let query man (type a) (q: a Queries.t): a Queries.result = S.query (conv man) q
96+
let assign man lv e = lift_fun man lift S.assign ((|>) e % (|>) lv)
97+
let vdecl man v = lift_fun man lift S.vdecl ((|>) v)
98+
let branch man e tv = lift_fun man lift S.branch ((|>) tv % (|>) e)
99+
let body man f = lift_fun man lift S.body ((|>) f)
100+
let return man r f = lift_fun man lift S.return ((|>) f % (|>) r)
101+
let asm man = lift_fun man lift S.asm identity
102+
let skip man = lift_fun man lift S.skip identity
103+
let special man r f args = lift_fun man lift S.special ((|>) args % (|>) f % (|>) r)
104+
105+
let enter man r f args =
106+
let liftmap = List.map (Tuple2.mapn lift) in
107+
lift_fun man liftmap S.enter ((|>) args % (|>) f % (|>) r)
108+
let combine_env man r fe f args fc es f_ask = lift_fun man lift S.combine_env (fun p -> p r fe f args fc (fst es) f_ask)
109+
let combine_assign man r fe f args fc es f_ask = lift_fun man lift S.combine_assign (fun p -> p r fe f args fc (fst es) f_ask)
110+
111+
let threadenter man ~multiple lval f args = lift_fun man (List.map lift) (S.threadenter ~multiple) ((|>) args % (|>) f % (|>) lval)
112+
let threadspawn man ~multiple lval f args fman = lift_fun man lift (S.threadspawn ~multiple) ((|>) (conv fman) % (|>) args % (|>) f % (|>) lval)
113+
114+
let paths_as_set man =
115+
let liftmap = List.map (fun x -> (x, snd man.local)) in
116+
lift_fun man liftmap S.paths_as_set Fun.id
117+
118+
let event man e oman =
119+
lift_fun man lift S.event ((|>) (conv oman) % (|>) e)
120+
end
121+
122+
(** Lift {!S} to use widening delay for global unknowns. *)
123+
module GLifter (S: Spec): Spec =
124+
struct
125+
module D = S.D
126+
module G =
127+
struct
128+
include Dom (S.G) (GlobalChainParams)
129+
130+
let printXml f (b, i) =
131+
BatPrintf.fprintf f "%a<analysis name=\"widen-delay\">%a</analysis>" S.G.printXml b Chain.printXml i
132+
end
133+
module C = S.C
134+
module V = S.V
135+
module P = S.P
136+
137+
let name () = S.name () ^ " with widening delay"
138+
139+
type marshal = S.marshal
140+
let init = S.init
141+
let finalize = S.finalize
142+
143+
let startstate v = S.startstate v
144+
let exitstate v = S.exitstate v
145+
let morphstate v d = S.morphstate v d
146+
147+
let conv (man: (D.t, G.t, C.t, V.t) man): (S.D.t, S.G.t, S.C.t, S.V.t) man =
148+
{ man with global = (fun v -> fst (man.global v))
149+
; sideg = (fun v g -> man.sideg v (g, 0))
150+
}
151+
152+
let context man fd d = S.context (conv man) fd d
153+
let startcontext () = S.startcontext ()
154+
155+
let lift_fun man f g h =
156+
f @@ h (g (conv man))
157+
158+
let lift d = d
159+
160+
let sync man reason = lift_fun man lift S.sync ((|>) reason)
161+
let query man (type a) (q: a Queries.t): a Queries.result = S.query (conv man) q
162+
let assign man lv e = lift_fun man lift S.assign ((|>) e % (|>) lv)
163+
let vdecl man v = lift_fun man lift S.vdecl ((|>) v)
164+
let branch man e tv = lift_fun man lift S.branch ((|>) tv % (|>) e)
165+
let body man f = lift_fun man lift S.body ((|>) f)
166+
let return man r f = lift_fun man lift S.return ((|>) f % (|>) r)
167+
let asm man = lift_fun man lift S.asm identity
168+
let skip man = lift_fun man lift S.skip identity
169+
let special man r f args = lift_fun man lift S.special ((|>) args % (|>) f % (|>) r)
170+
171+
let enter man r f args =
172+
let liftmap = List.map (Tuple2.mapn lift) in
173+
lift_fun man liftmap S.enter ((|>) args % (|>) f % (|>) r)
174+
let combine_env man r fe f args fc es f_ask = lift_fun man lift S.combine_env (fun p -> p r fe f args fc es f_ask)
175+
let combine_assign man r fe f args fc es f_ask = lift_fun man lift S.combine_assign (fun p -> p r fe f args fc es f_ask)
176+
177+
let threadenter man ~multiple lval f args = lift_fun man (List.map lift) (S.threadenter ~multiple) ((|>) args % (|>) f % (|>) lval)
178+
let threadspawn man ~multiple lval f args fman = lift_fun man lift (S.threadspawn ~multiple) ((|>) (conv fman) % (|>) args % (|>) f % (|>) lval)
179+
180+
let paths_as_set man =
181+
lift_fun man Fun.id S.paths_as_set Fun.id
182+
183+
let event man e oman =
184+
lift_fun man lift S.event ((|>) (conv oman) % (|>) e)
185+
end

0 commit comments

Comments
 (0)