Skip to content

Commit f8dd735

Browse files
fixed misbehaviour of join wrt bot values and added a regression for this
1 parent 36f9f2d commit f8dd735

2 files changed

Lines changed: 73 additions & 18 deletions

File tree

src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml

Lines changed: 27 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -396,6 +396,10 @@ struct
396396
(** is_top returns true for top_of array and empty array; precondition: t.env and t.d are of same size *)
397397
let is_top t = GobOption.exists EConj.is_top_con t.d
398398

399+
let is_top_env t = (not @@ Environment.equal empty_env t.env) && GobOption.exists EConj.is_top_con t.d
400+
401+
(** is_bot_env returns true for empty env and empty d *)
402+
399403
let to_subscript i =
400404
let transl = [|"";"";"";"";"";"";"";"";"";""|] in
401405
let rec subscr i =
@@ -466,8 +470,8 @@ struct
466470
| Some (coeffj,j) -> tuple_cmp (EConj.get_rhs ts i) @@ Rhs.subst (EConj.get_rhs ts j) j (var, offs, divi)
467471
in
468472
if env_comp = -2 || env_comp > 0 then false else
469-
if is_bot_env t1 || is_top t2 then true
470-
else if is_bot_env t2 || is_top t1 then false else
473+
if is_bot_env t1 || is_top_env t2 then true
474+
else if is_bot_env t2 || is_top_env t1 then false else
471475
let m1, m2 = Option.get t1.d, Option.get t2.d in
472476
let m1' = if env_comp = 0 then m1 else VarManagement.dim_add (Environment.dimchange t1.env t2.env) m1 in
473477
EConj.IntMap.for_all (implies m1') (snd m2) (* even on sparse m2, it suffices to check the non-trivial equalities, still present in sparse m2 *)
@@ -534,19 +538,24 @@ struct
534538

535539
in
536540
(*Normalize the two domains a and b such that both talk about the same variables*)
537-
match a.d, b.d with
538-
| None, _ -> b
539-
| _, None -> a
540-
| Some x, Some y when is_top a || is_top b ->
541-
let new_env = Environment.lce a.env b.env in
542-
top_of new_env
543-
| Some x, Some y when (Environment.cmp a.env b.env <> 0) ->
544-
let sup_env = Environment.lce a.env b.env in
545-
let mod_x = dim_add (Environment.dimchange a.env sup_env) x in
546-
let mod_y = dim_add (Environment.dimchange b.env sup_env) y in
547-
{d = join_d mod_x mod_y; env = sup_env}
548-
| Some x, Some y when EConj.equal x y -> {d = Some x; env = a.env}
549-
| Some x, Some y -> {d = join_d x y; env = a.env}
541+
if is_bot a then
542+
b
543+
else if is_bot b then
544+
a
545+
else
546+
match a.d, b.d with
547+
| None, _ -> b
548+
| _, None -> a
549+
| Some x, Some y when is_top_env a || is_top_env b ->
550+
let new_env = Environment.lce a.env b.env in
551+
top_of new_env
552+
| Some x, Some y when (Environment.cmp a.env b.env <> 0) ->
553+
let sup_env = Environment.lce a.env b.env in
554+
let mod_x = dim_add (Environment.dimchange a.env sup_env) x in
555+
let mod_y = dim_add (Environment.dimchange b.env sup_env) y in
556+
{d = join_d mod_x mod_y; env = sup_env}
557+
| Some x, Some y when EConj.equal x y -> {d = Some x; env = a.env}
558+
| Some x, Some y -> {d = join_d x y; env = a.env}
550559

551560
let join a b = Timing.wrap "join" (join a) b
552561

@@ -574,12 +583,12 @@ struct
574583
dprintf "%s: %a not leq %a" (name ()) pretty x pretty y
575584

576585
let forget_var t var =
577-
if is_bot_env t || is_top t then t
586+
if is_bot_env t || is_top_env t then t
578587
else
579588
{d = Some (EConj.forget_variable (Option.get t.d) (Environment.dim_of_var t.env var)); env = t.env}
580589

581590
let forget_vars t vars =
582-
if is_bot_env t || is_top t || List.is_empty vars then
591+
if is_bot_env t || is_top_env t || List.is_empty vars then
583592
t
584593
else
585594
let newm = List.fold (fun map i -> EConj.forget_variable map (Environment.dim_of_var t.env i)) (Option.get t.d) vars in
@@ -651,7 +660,7 @@ struct
651660
let t_primed = add_vars t primed_vars in
652661
let multi_t = List.fold_left2 (fun t' v_prime (_,v') -> assign_var t' v_prime v') t_primed primed_vars vv's in
653662
match multi_t.d with
654-
| Some arr when not @@ is_top multi_t ->
663+
| Some arr when not @@ is_top_env multi_t ->
655664
let switched_arr = List.fold_left2 (fun multi_t assigned_var primed_var-> assign_var multi_t assigned_var primed_var) multi_t assigned_vars primed_vars in
656665
remove_vars switched_arr primed_vars
657666
| _ -> t
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
// SKIP PARAM: --set ana.activated[+] lin2vareq --set ana.path_sens[+] threadflag --set ana.relation.privatization mutex-meet-tid
2+
// This is basically the same as 36-apron/71-tid-toy1.c, and is the first lin2vareq regression test using privatization
3+
// incorrect handling of is_bot_env and is_top_env can lead this regression test to fail
4+
5+
#include <pthread.h>
6+
#include <goblint.h>
7+
8+
int g = 10;
9+
int h = 10;
10+
pthread_mutex_t A = PTHREAD_MUTEX_INITIALIZER;
11+
12+
void *t_fun(void *arg) {
13+
int t, r; // rand
14+
pthread_mutex_lock(&A);
15+
g = t;
16+
h = t;
17+
pthread_mutex_unlock(&A);
18+
return NULL;
19+
}
20+
21+
int main(void) {
22+
int t;
23+
24+
pthread_t id;
25+
pthread_create(&id, NULL, t_fun, NULL);
26+
27+
pthread_mutex_lock(&A);
28+
g = 31;
29+
h = 17;
30+
pthread_mutex_unlock(&A);
31+
32+
pthread_mutex_lock(&A);
33+
__goblint_check(g == h); //UNKNOWN!
34+
pthread_mutex_unlock(&A);
35+
36+
pthread_mutex_lock(&A);
37+
g = t;
38+
h = t;
39+
pthread_mutex_unlock(&A);
40+
41+
pthread_mutex_lock(&A);
42+
__goblint_check(g == h); // t_fun always has the invariant it only is violated in main temporarily
43+
pthread_mutex_unlock(&A);
44+
45+
return 0;
46+
}

0 commit comments

Comments
 (0)