Skip to content

Commit e082d52

Browse files
authored
Merge pull request #1873 from goblint/apron-invariant-diff-box-direct
Implement `ana.apron.invariant.diff-box` directly in domain
2 parents aeb3c2e + e7ef764 commit e082d52

File tree

5 files changed

+122
-212
lines changed

5 files changed

+122
-212
lines changed

src/analyses/apron/apronAnalysis.apron.ml

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,6 @@ let spec_module: (module MCPSpec) Lazy.t =
88
lazy (
99
let module Man = (val ApronDomain.get_manager ()) in
1010
let module AD = ApronDomain.D2 (Man) in
11-
let diff_box = GobConfig.get_bool "ana.apron.invariant.diff-box" in
12-
let module AD = (val if diff_box then (module ApronDomain.BoxProd (AD): RelationDomain.RD) else (module AD)) in
1311
let module Priv = (val RelationPriv.get_priv ()) in
1412
let module Spec =
1513
struct

src/cdomains/apron/apronDomain.apron.ml

Lines changed: 28 additions & 116 deletions
Original file line numberDiff line numberDiff line change
@@ -544,17 +544,37 @@ struct
544544
d
545545
end
546546

547-
let invariant x =
547+
(** Keep only box-representable constraints.
548+
Used for [diff-box] in {!invariant}. *)
549+
let boxify d =
550+
let {box1_env; interval_array}: A.box1 = A.to_box Man.mgr d in
551+
let ivs, fvs = Environment.vars box1_env in
552+
assert (Array.length fvs = 0); (* shouldn't ever contain floats *)
553+
A.of_box Man.mgr box1_env ivs interval_array
554+
555+
let to_lincons_set d =
556+
Lincons1Set.of_earray (A.to_lincons_array Man.mgr d)
557+
558+
let invariant d =
548559
(* Would like to minimize to get rid of multi-var constraints directly derived from one-var constraints,
549560
but not implemented in Apron at all: https://github.com/antoinemine/apron/issues/44 *)
550-
(* let x = A.copy Man.mgr x in
551-
A.minimize Man.mgr x; *)
552-
let {lincons0_array; array_env}: Lincons1.earray = A.to_lincons_array Man.mgr x in
553-
Array.to_seq lincons0_array
554-
|> Seq.map (fun (lincons0: Lincons0.t) -> Lincons1.{lincons0; env = array_env})
555-
|> Lincons1Set.of_seq
561+
(* let d = A.copy Man.mgr d in
562+
A.minimize Man.mgr d; *)
563+
let lcd = to_lincons_set d in
564+
if GobConfig.get_bool "ana.apron.invariant.diff-box" then (
565+
(* diff via lincons *)
566+
(* TODO: is there benefit to also Lincons1Set.simplify before diff? might make a difference if y=0 is represented as y>=0 && y<=0 or not *)
567+
let b = boxify d in (* convert back to same Apron domain (instead of box) to make lincons use the same format (e.g. oct doesn't return equalities, but box does) *)
568+
let lcb = to_lincons_set b in
569+
Lincons1Set.diff lcd lcb
570+
)
571+
else
572+
lcd
573+
574+
let invariant d =
575+
invariant d
556576
|> (if Oct.manager_is_oct Man.mgr then Lincons1Set.simplify else Fun.id)
557-
|> Lincons1Set.elements
577+
|> Lincons1Set.elements (* TODO: remove list conversion? *)
558578
end
559579

560580
(** With heterogeneous environments. *)
@@ -836,111 +856,3 @@ struct
836856

837857
let unmarshal (m: marshal) = Oct.Abstract1.of_oct @@ OctagonD.unmarshal m
838858
end
839-
840-
(** Lift [D] to a non-reduced product with box.
841-
Both are updated in parallel, but [D] answers to queries.
842-
Box domain is used to filter out non-relational invariants for output. *)
843-
module BoxProd0 (D: S3) =
844-
struct
845-
module BoxD = D2 (IntervalManager)
846-
847-
include Printable.Prod (BoxD) (D)
848-
849-
let equal (_, d1) (_, d2) = D.equal d1 d2
850-
let hash (_, d) = D.hash d
851-
let compare (_, d1) (_, d2) = D.compare d1 d2
852-
853-
let leq (_, d1) (_, d2) = D.leq d1 d2
854-
let join (b1, d1) (b2, d2) = (BoxD.join b1 b2, D.join d1 d2)
855-
let meet (b1, d1) (b2, d2) = (BoxD.meet b1 b2, D.meet d1 d2)
856-
let widen (b1, d1) (b2, d2) = (BoxD.widen b1 b2, D.widen d1 d2)
857-
let narrow (b1, d1) (b2, d2) = (BoxD.narrow b1 b2, D.narrow d1 d2)
858-
859-
let top () = (BoxD.top (), D.top ())
860-
let bot () = (BoxD.bot (), D.bot ())
861-
let is_top (_, d) = D.is_top d
862-
let is_bot (_, d) = D.is_bot d
863-
let top_env env = (BoxD.top_env env, D.top_env env)
864-
let bot_env env = (BoxD.bot_env env, D.bot_env env)
865-
let is_top_env (_, d) = D.is_top_env d
866-
let is_bot_env (_, d) = D.is_bot_env d
867-
let unify (b1, d1) (b2, d2) = (BoxD.unify b1 b2, D.unify d1 d2)
868-
let copy (b, d) = (BoxD.copy b, D.copy d)
869-
870-
type marshal = BoxD.marshal * D.marshal
871-
872-
let marshal (b, d) = (BoxD.marshal b, D.marshal d)
873-
let unmarshal (b, d) = (BoxD.unmarshal b, D.unmarshal d)
874-
875-
let mem_var (_, d) v = D.mem_var d v
876-
let vars (_, d) = D.vars d
877-
878-
let pretty_diff () ((_, d1), (_, d2)) = D.pretty_diff () (d1, d2)
879-
880-
let add_vars_with (b, d) vs =
881-
BoxD.add_vars_with b vs;
882-
D.add_vars_with d vs
883-
let remove_vars_with (b, d) vs =
884-
BoxD.remove_vars_with b vs;
885-
D.remove_vars_with d vs
886-
let remove_filter_with (b, d) f =
887-
BoxD.remove_filter_with b f;
888-
D.remove_filter_with d f
889-
let keep_filter_with (b, d) f =
890-
BoxD.keep_filter_with b f;
891-
D.keep_filter_with d f
892-
let keep_vars_with (b, d) vs =
893-
BoxD.keep_vars_with b vs;
894-
D.keep_vars_with d vs
895-
let forget_vars_with (b, d) vs =
896-
BoxD.forget_vars_with b vs;
897-
D.forget_vars_with d vs
898-
let assign_exp_with ask (b, d) v e no_ov =
899-
BoxD.assign_exp_with ask b v e no_ov;
900-
D.assign_exp_with ask d v e no_ov
901-
let assign_exp_parallel_with ask (b, d) ves no_ov =
902-
BoxD.assign_exp_parallel_with ask b ves no_ov;
903-
D.assign_exp_parallel_with ask d ves no_ov
904-
let assign_var_with (b, d) v e =
905-
BoxD.assign_var_with b v e;
906-
D.assign_var_with d v e
907-
let assign_var_parallel_with (b, d) vvs =
908-
BoxD.assign_var_parallel_with b vvs;
909-
D.assign_var_parallel_with d vvs
910-
let assign_var_parallel' (b, d) vs v's =
911-
(BoxD.assign_var_parallel' b vs v's, D.assign_var_parallel' d vs v's)
912-
let substitute_exp_with ask (b, d) v e no_ov =
913-
BoxD.substitute_exp_with ask b v e no_ov;
914-
D.substitute_exp_with ask d v e no_ov
915-
let substitute_exp_parallel_with ask (b, d) ves no_ov =
916-
BoxD.substitute_exp_parallel_with ask b ves no_ov;
917-
D.substitute_exp_parallel_with ask d ves no_ov
918-
let substitute_var_with (b, d) v1 v2 =
919-
BoxD.substitute_var_with b v1 v2;
920-
D.substitute_var_with d v1 v2
921-
let meet_tcons ask (b, d) c e = (BoxD.meet_tcons ask b c e, D.meet_tcons ask d c e)
922-
let to_lincons_array (_, d) = D.to_lincons_array d
923-
let of_lincons_array a = (BoxD.of_lincons_array a, D.of_lincons_array a)
924-
925-
let cil_exp_of_lincons1 = D.cil_exp_of_lincons1
926-
let assert_inv ask (b, d) e n no_ov = (BoxD.assert_inv ask b e n no_ov, D.assert_inv ask d e n no_ov)
927-
let eval_int ask (_, d) = D.eval_int ask d
928-
929-
let invariant (b, d) =
930-
(* diff via lincons *)
931-
let lcb = D.to_lincons_array (D.of_lincons_array (BoxD.to_lincons_array b)) in (* convert through D to make lincons use the same format *)
932-
let lcd = D.to_lincons_array d in
933-
Lincons1Set.(diff (of_earray lcd) (of_earray lcb))
934-
|> (if Oct.manager_is_oct D.Man.mgr then Lincons1Set.simplify else Fun.id)
935-
|> Lincons1Set.elements
936-
end
937-
938-
module BoxProd (D: S3): RD =
939-
struct
940-
module V = D.V
941-
type var = V.t
942-
module BP0 = BoxProd0 (D)
943-
module Tracked = SharedFunctions.Tracked
944-
include BP0
945-
include AOpsPureOfImperative (BP0)
946-
end

tests/regression/36-apron/01-octagon_simple.t

Lines changed: 37 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -196,7 +196,7 @@ With diff-box:
196196
[Warning][Deadcode][CWE-571] condition '1' (possibly inserted by CIL) is always true (01-octagon_simple.c:44:10-44:11)
197197
[Info][Witness] witness generation summary:
198198
location invariants: 0
199-
loop invariants: 6
199+
loop invariants: 2
200200
flow-insensitive invariants: 0
201201
total generation entries: 1
202202

@@ -212,24 +212,6 @@ With diff-box:
212212
function: main
213213
value: (long long )N >= (long long )X
214214
format: c_expression
215-
- invariant:
216-
type: loop_invariant
217-
location:
218-
file_name: 01-octagon_simple.c
219-
line: 10
220-
column: 3
221-
function: main
222-
value: 2147483647LL >= (long long )X
223-
format: c_expression
224-
- invariant:
225-
type: loop_invariant
226-
location:
227-
file_name: 01-octagon_simple.c
228-
line: 10
229-
column: 3
230-
function: main
231-
value: 4294967294LL >= (long long )X + (long long )N
232-
format: c_expression
233215
- invariant:
234216
type: loop_invariant
235217
location:
@@ -239,29 +221,29 @@ With diff-box:
239221
function: two
240222
value: (long long )N >= (long long )X
241223
format: c_expression
242-
- invariant:
243-
type: loop_invariant
244-
location:
245-
file_name: 01-octagon_simple.c
246-
line: 44
247-
column: 3
248-
function: two
249-
value: 2147483647LL >= (long long )X
250-
format: c_expression
251-
- invariant:
252-
type: loop_invariant
253-
location:
254-
file_name: 01-octagon_simple.c
255-
line: 44
256-
column: 3
257-
function: two
258-
value: 4294967294LL >= (long long )X + (long long )N
259-
format: c_expression
260224

261225
Compare witnesses:
262226

263227
$ yamlWitnessStripDiff witness-disable-diff-box.yml witness-enable-diff-box.yml
264228
# Left-only invariants:
229+
- invariant:
230+
type: loop_invariant
231+
location:
232+
file_name: 01-octagon_simple.c
233+
line: 44
234+
column: 3
235+
function: two
236+
value: 4294967294LL >= (long long )X + (long long )N
237+
format: c_expression
238+
- invariant:
239+
type: loop_invariant
240+
location:
241+
file_name: 01-octagon_simple.c
242+
line: 44
243+
column: 3
244+
function: two
245+
value: 2147483647LL >= (long long )X
246+
format: c_expression
265247
- invariant:
266248
type: loop_invariant
267249
location:
@@ -307,6 +289,24 @@ Compare witnesses:
307289
function: two
308290
value: (long long )N >= 0LL
309291
format: c_expression
292+
- invariant:
293+
type: loop_invariant
294+
location:
295+
file_name: 01-octagon_simple.c
296+
line: 10
297+
column: 3
298+
function: main
299+
value: 4294967294LL >= (long long )X + (long long )N
300+
format: c_expression
301+
- invariant:
302+
type: loop_invariant
303+
location:
304+
file_name: 01-octagon_simple.c
305+
line: 10
306+
column: 3
307+
function: main
308+
value: 2147483647LL >= (long long )X
309+
format: c_expression
310310
- invariant:
311311
type: loop_invariant
312312
location:

tests/regression/36-apron/52-queuesize.t

Lines changed: 20 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,7 @@ With diff-box:
160160
[Warning][Deadcode][CWE-571] condition '1' (possibly inserted by CIL) is always true (52-queuesize.c:56:10-56:11)
161161
[Warning][Deadcode][CWE-571] condition '1' (possibly inserted by CIL) is always true (52-queuesize.c:78:12-78:13)
162162
[Info][Witness] witness generation summary:
163-
location invariants: 6
163+
location invariants: 4
164164
loop invariants: 0
165165
flow-insensitive invariants: 0
166166
total generation entries: 1
@@ -170,6 +170,7 @@ With diff-box:
170170
unsafe: 0
171171
total memory locations: 3
172172

173+
TODO: Should (long long )free >= 0LL somehow still remain, because it cannot be inferred by box alone?
173174
$ yamlWitnessStrip < witness.yml | tee witness-enable-diff-box.yml
174175
- entry_type: invariant_set
175176
content:
@@ -182,15 +183,6 @@ With diff-box:
182183
function: pop
183184
value: (long long )capacity >= (long long )free
184185
format: c_expression
185-
- invariant:
186-
type: location_invariant
187-
location:
188-
file_name: 52-queuesize.c
189-
line: 15
190-
column: 3
191-
function: pop
192-
value: (long long )free >= 0LL
193-
format: c_expression
194186
- invariant:
195187
type: location_invariant
196188
location:
@@ -209,15 +201,6 @@ With diff-box:
209201
function: push
210202
value: (long long )capacity >= (long long )free
211203
format: c_expression
212-
- invariant:
213-
type: location_invariant
214-
location:
215-
file_name: 52-queuesize.c
216-
line: 36
217-
column: 3
218-
function: push
219-
value: (long long )free >= 0LL
220-
format: c_expression
221204
- invariant:
222205
type: location_invariant
223206
location:
@@ -241,6 +224,15 @@ Compare witnesses:
241224
function: push
242225
value: 2147483647LL >= (long long )capacity
243226
format: c_expression
227+
- invariant:
228+
type: location_invariant
229+
location:
230+
file_name: 52-queuesize.c
231+
line: 36
232+
column: 3
233+
function: push
234+
value: (long long )free >= 0LL
235+
format: c_expression
244236
- invariant:
245237
type: location_invariant
246238
location:
@@ -250,4 +242,13 @@ Compare witnesses:
250242
function: pop
251243
value: 2147483647LL >= (long long )capacity
252244
format: c_expression
245+
- invariant:
246+
type: location_invariant
247+
location:
248+
file_name: 52-queuesize.c
249+
line: 15
250+
column: 3
251+
function: pop
252+
value: (long long )free >= 0LL
253+
format: c_expression
253254
---

0 commit comments

Comments
 (0)