From 75503af6f30e487ea08206e65bbc19f07d20f599 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Mon, 27 Sep 2021 14:07:41 +0300 Subject: [PATCH 001/402] Add side restart example --- tests/regression/02-base/64-side-restart.c | 26 ++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 tests/regression/02-base/64-side-restart.c diff --git a/tests/regression/02-base/64-side-restart.c b/tests/regression/02-base/64-side-restart.c new file mode 100644 index 0000000000..1acf23b768 --- /dev/null +++ b/tests/regression/02-base/64-side-restart.c @@ -0,0 +1,26 @@ +// PARAM: --enable ana.int.interval +#include +#include + +int g; + +void* t_fun(void *arg) { + int x = g; + assert(x <= 8); + return NULL; +} + +int main() { + pthread_t id; + pthread_create(&id, NULL, t_fun, NULL); + + int i = 0; + int j; + + for (j = 1; j < 10; j++) { + for (i = 0; i < j; i++) { + g = i; + } + } + return 0; +} \ No newline at end of file From a977dcffe3bcb7e408b6dac7fe654d7ea74b39b7 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Mon, 27 Sep 2021 17:08:36 +0300 Subject: [PATCH 002/402] Add TD3 globals restarting phase --- src/solvers/td3.ml | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/src/solvers/td3.ml b/src/solvers/td3.ml index 010483280d..baa83cabd4 100644 --- a/src/solvers/td3.ml +++ b/src/solvers/td3.ml @@ -79,6 +79,8 @@ module WP = let wpoint = data.wpoint in let stable = data.stable in + let side_dep = HM.create 10 in + let () = print_solver_stats := fun () -> Printf.printf "|rho|=%d\n|called|=%d\n|stable|=%d\n|infl|=%d\n|wpoint|=%d\n" (HM.length rho) (HM.length called) (HM.length stable) (HM.length infl) (HM.length wpoint); @@ -102,6 +104,14 @@ module WP = HM.remove stable y; if not (HM.mem called y) then destabilize y ) w + and destabilize_side x = + if tracing then trace "sol2" "destabilize_side %a\n" S.Var.pretty_trace x; + let w = HM.find_default side_dep x VS.empty in + HM.replace side_dep x VS.empty; + VS.iter (fun y -> + HM.remove stable y; + if not (HM.mem called y) then destabilize y + ) w and destabilize_vs x = (* TODO remove? Only used for side_widen cycle. *) if tracing then trace "sol2" "destabilize_vs %a\n" S.Var.pretty_trace x; let w = HM.find_default infl x VS.empty in @@ -184,6 +194,7 @@ module WP = ); assert (S.system y = None); init y; + HM.replace side_dep y (VS.add x (try HM.find side_dep y with Not_found -> VS.empty)); if side_widen = "unstable_self" then add_infl x y; let op = if HM.mem wpoint y then fun a b -> @@ -324,6 +335,25 @@ module WP = ) in solver (); + + Printf.printf "Restarting globals\n"; + if tracing then trace "sol2" "Restarting globals\n"; + HM.iter (fun x _ -> + (* TODO: hack to identify globals *) + if Node.equal (S.Var.node x) (Function Cil.dummyFunDec) then ( + if tracing then trace "sol2" "Restarting global %a\n" S.Var.pretty_trace x; + HM.replace rho x (S.Dom.bot ()); + (* HM.remove rho x; *) + HM.remove wpoint x; (* otherwise gets immediately widened during resolve *) + HM.remove sides x; (* just in case *) + destabilize x; + destabilize_side x; + ) + ) rho; + + List.iter set_start st; (* TODO: necessary? *) + (* List.iter init vs; *) + solver (); (* Before we solved all unstable vars in rho with a rhs in a loop. This is unneeded overhead since it also solved unreachable vars (reachability only removes those from rho further down). *) (* After termination, only those variables are stable which are * - reachable from any of the queried variables vs, or From 47c561f70d1f1664d48b64f957c466ed69a02ba7 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Mon, 27 Sep 2021 17:09:34 +0300 Subject: [PATCH 003/402] Add tests for restarting dependent side effects --- .../02-base/65-side-restart-mutual.c | 35 +++++++++++++++++++ .../regression/02-base/66-side-restart-self.c | 23 ++++++++++++ 2 files changed, 58 insertions(+) create mode 100644 tests/regression/02-base/65-side-restart-mutual.c create mode 100644 tests/regression/02-base/66-side-restart-self.c diff --git a/tests/regression/02-base/65-side-restart-mutual.c b/tests/regression/02-base/65-side-restart-mutual.c new file mode 100644 index 0000000000..4305eb534e --- /dev/null +++ b/tests/regression/02-base/65-side-restart-mutual.c @@ -0,0 +1,35 @@ +// PARAM: --enable ana.int.interval +#include +#include + +int g, h; + +void* t_fun(void *arg) { + int x = g; + if (x < 10) { + x++; + h = x; + } + return NULL; +} + +void* t_fun2(void *arg) { + int y = h; + if (y < 10) { + y++; + g = y; + } + return NULL; +} + +int main() { + pthread_t id, id2; + pthread_create(&id, NULL, t_fun, NULL); + pthread_create(&id2, NULL, t_fun2, NULL); + + int x = g; + int y = h; + assert(x <= 10); + assert(y <= 10); + return 0; +} \ No newline at end of file diff --git a/tests/regression/02-base/66-side-restart-self.c b/tests/regression/02-base/66-side-restart-self.c new file mode 100644 index 0000000000..dbdea875d7 --- /dev/null +++ b/tests/regression/02-base/66-side-restart-self.c @@ -0,0 +1,23 @@ +// PARAM: --enable ana.int.interval +#include +#include + +int g; + +void* t_fun(void *arg) { + int x = g; + if (x < 10) { + x++; + g = x; + } + return NULL; +} + +int main() { + pthread_t id; + pthread_create(&id, NULL, t_fun, NULL); + + int x = g; + assert(x <= 10); + return 0; +} \ No newline at end of file From f04fddcd3a5c4ce9a8b31613058972b4f2eb3d00 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Tue, 28 Sep 2021 09:59:58 +0300 Subject: [PATCH 004/402] Try single global restarting by hardcoding --- src/solvers/td3.ml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/solvers/td3.ml b/src/solvers/td3.ml index baa83cabd4..6cd2258370 100644 --- a/src/solvers/td3.ml +++ b/src/solvers/td3.ml @@ -340,7 +340,7 @@ module WP = if tracing then trace "sol2" "Restarting globals\n"; HM.iter (fun x _ -> (* TODO: hack to identify globals *) - if Node.equal (S.Var.node x) (Function Cil.dummyFunDec) then ( + if Node.equal (S.Var.node x) (Function Cil.dummyFunDec) (* && (String.starts_with (Pretty.sprint ~width:max_int (S.Var.pretty_trace () x))"bwritten on") *) then ( if tracing then trace "sol2" "Restarting global %a\n" S.Var.pretty_trace x; HM.replace rho x (S.Dom.bot ()); (* HM.remove rho x; *) From 792aa48484f4347ad414f851f560a7e98e7a78b0 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Tue, 28 Sep 2021 10:32:59 +0300 Subject: [PATCH 005/402] Add bool changed component to TD3 solve & eval --- src/solvers/td3.ml | 53 ++++++++++++++++++++++++---------------------- 1 file changed, 28 insertions(+), 25 deletions(-) diff --git a/src/solvers/td3.ml b/src/solvers/td3.ml index 010483280d..b04fa40eee 100644 --- a/src/solvers/td3.ml +++ b/src/solvers/td3.ml @@ -70,7 +70,7 @@ module WP = let term = GobConfig.get_bool "exp.solver.td3.term" in let side_widen = GobConfig.get_string "exp.solver.td3.side_widen" in let space = GobConfig.get_bool "exp.solver.td3.space" in - let cache = GobConfig.get_bool "exp.solver.td3.space_cache" in + (* let cache = GobConfig.get_bool "exp.solver.td3.space_cache" in *) let called = HM.create 10 in let infl = data.infl in @@ -111,7 +111,7 @@ module WP = HM.remove stable y; HM.mem called y || destabilize_vs y || b || was_stable && List.mem y vs ) w false - and solve x phase = + and solve x phase: bool = if tracing then trace "sol2" "solve %a, called: %b, stable: %b\n" S.Var.pretty_trace x (HM.mem called x) (HM.mem stable x); init x; assert (S.system x <> None); @@ -141,36 +141,39 @@ module WP = if tracing then trace "sol" "New Value:%a\n\n" S.Dom.pretty tmp; HM.replace rho x tmp; destabilize x; - (solve[@tailcall]) x phase; - ) else if not (HM.mem stable x) then ( - (solve[@tailcall]) x Widen; - ) else if term && phase = Widen then ( - HM.remove stable x; - (solve[@tailcall]) x Narrow; - ) else if not space && (not term || phase = Narrow) then (* this makes e.g. nested loops precise, ex. tests/regression/34-localization/01-nested.c - if we do not remove wpoint, the inner loop head will stay a wpoint and widen the outer loop variable. *) - HM.remove wpoint x; + (* (solve[@tailcall]) x phase; *) + ignore (solve x phase); + true + ) else ( + if not (HM.mem stable x) then ( + (solve[@tailcall]) x Widen + ) else if term && phase = Widen then ( + HM.remove stable x; + (solve[@tailcall]) x Narrow + ) else if not space && (not term || phase = Narrow) then ( (* this makes e.g. nested loops precise, ex. tests/regression/34-localization/01-nested.c - if we do not remove wpoint, the inner loop head will stay a wpoint and widen the outer loop variable. *) + HM.remove wpoint x; + false + ) + else + false + ) ) + else if HM.mem called x then + true + else + false and eq x get set = if tracing then trace "sol2" "eq %a\n" S.Var.pretty_trace x; eval_rhs_event x; match S.system x with | None -> S.Dom.bot () | Some f -> f get set - and simple_solve l x y = + and simple_solve l x y: S.d * bool = if tracing then trace "sol2" "simple_solve %a (rhs: %b)\n" S.Var.pretty_trace y (S.system y <> None); - if S.system y = None then (init y; HM.find rho y) else - if HM.mem rho y || not space then (solve y Widen; HM.find rho y) else - if HM.mem called y then (init y; HM.remove l y; HM.find rho y) else - (* if HM.mem called y then (init y; let y' = HM.find_default l y (S.Dom.bot ()) in HM.replace rho y y'; HM.remove l y; y') else *) - if cache && HM.mem l y then HM.find l y - else ( - HM.replace called y (); - let tmp = eq y (eval l x) (side x) in - HM.remove called y; - if HM.mem rho y then (HM.remove l y; solve y Widen; HM.find rho y) - else (if cache then HM.replace l y tmp; tmp) - ) - and eval l x y = + if S.system y = None then (init y; (HM.find rho y, true (* TODO: ??? *))) else + if HM.mem rho y || not space then (let changed = solve y Widen in (HM.find rho y, changed)) else + failwith "space abort unimplemented" + and eval l x y: S.d * bool = if tracing then trace "sol2" "eval %a ## %a\n" S.Var.pretty_trace x S.Var.pretty_trace y; get_var_event y; if HM.mem called y then HM.replace wpoint y (); @@ -319,7 +322,7 @@ module WP = print_newline (); flush_all (); ); - List.iter (fun x -> solve x Widen) unstable_vs; + List.iter (fun x -> ignore (solve x Widen)) unstable_vs; solver (); ) in From 740b72c6d0af932e7e6d7a07e4db5b7e2f03fc5e Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Tue, 28 Sep 2021 10:34:22 +0300 Subject: [PATCH 006/402] Add dep hashtable to TD3 This collects the dependencies of a variable (opposite of infl). --- src/solvers/td3.ml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/solvers/td3.ml b/src/solvers/td3.ml index b04fa40eee..c06e97ebbc 100644 --- a/src/solvers/td3.ml +++ b/src/solvers/td3.ml @@ -74,6 +74,7 @@ module WP = let called = HM.create 10 in let infl = data.infl in + let dep = HM.create 10 in let sides = data.sides in let rho = data.rho in let wpoint = data.wpoint in @@ -91,7 +92,8 @@ module WP = let add_infl y x = if tracing then trace "sol2" "add_infl %a %a\n" S.Var.pretty_trace y S.Var.pretty_trace x; - HM.replace infl y (VS.add x (try HM.find infl y with Not_found -> VS.empty)) + HM.replace infl y (VS.add x (try HM.find infl y with Not_found -> VS.empty)); + HM.replace dep x (VS.add y (try HM.find dep x with Not_found -> VS.empty)); in let add_sides y x = HM.replace sides y (VS.add x (try HM.find infl y with Not_found -> VS.empty)) in let rec destabilize x = @@ -99,6 +101,7 @@ module WP = let w = HM.find_default infl x VS.empty in HM.replace infl x VS.empty; VS.iter (fun y -> + (* TODO: remove from dep? *) HM.remove stable y; if not (HM.mem called y) then destabilize y ) w @@ -107,6 +110,7 @@ module WP = let w = HM.find_default infl x VS.empty in HM.replace infl x VS.empty; VS.fold (fun y b -> + (* TODO: remove from dep? *) let was_stable = HM.mem stable y in HM.remove stable y; HM.mem called y || destabilize_vs y || b || was_stable && List.mem y vs From 342cfa0ab8f96d9397d72873e7fac2ce72524a7f Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Tue, 28 Sep 2021 10:38:25 +0300 Subject: [PATCH 007/402] Add aborting via exception to TD3 --- src/solvers/td3.ml | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/src/solvers/td3.ml b/src/solvers/td3.ml index c06e97ebbc..1df694c1c3 100644 --- a/src/solvers/td3.ml +++ b/src/solvers/td3.ml @@ -66,6 +66,8 @@ module WP = type phase = Widen | Narrow + exception AbortEq + let solve box st vs data = let term = GobConfig.get_bool "exp.solver.td3.term" in let side_widen = GobConfig.get_string "exp.solver.td3.side_widen" in @@ -125,7 +127,33 @@ module WP = let wp = HM.mem wpoint x in let old = HM.find rho x in let l = HM.create 10 in - let tmp = eq x (eval l x) (side x) in + let eval' = + if HM.mem dep x then ( + let unasked_dep_x = ref (HM.find dep x) in + let all_dep_x_unchanged = ref true in + fun y -> + let (d, changed) = eval l x y in + if VS.mem y !unasked_dep_x then ( + unasked_dep_x := VS.remove y !unasked_dep_x; + if changed then + all_dep_x_unchanged := false; + if VS.is_empty !unasked_dep_x && !all_dep_x_unchanged then + raise AbortEq + ); + d + ) + else + fun y -> + let (d, changed) = eval l x y in + d + in + let tmp = + try + eq x eval' (side x) + with AbortEq -> + if tracing then trace "sol2" "eq aborted %a\n" S.Var.pretty_trace x; + old + in (* let tmp = if GobConfig.get_bool "ana.opt.hashcons" then S.Dom.join (S.Dom.bot ()) tmp else tmp in (* Call hashcons via dummy join so that the tag of the rhs value is up to date. Otherwise we might get the same value as old, but still with a different tag (because no lattice operation was called after a change), and since Printable.HConsed.equal just looks at the tag, we would uneccessarily destabilize below. Seems like this does not happen. *) *) if tracing then trace "sol" "Var: %a\n" S.Var.pretty_trace x ; if tracing then trace "sol" "Contrib:%a\n" S.Dom.pretty tmp; From 7c6f6438c227cf885b3aeb9ba9a3e51c6410197e Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Tue, 28 Sep 2021 10:39:12 +0300 Subject: [PATCH 008/402] Fix FromSpec not resetting current globals on TD3 eq abort --- src/framework/constraints.ml | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/src/framework/constraints.ml b/src/framework/constraints.ml index b090650891..d38836c239 100644 --- a/src/framework/constraints.ml +++ b/src/framework/constraints.ml @@ -681,10 +681,13 @@ struct let old_loc2 = !Tracing.next_loc in let _ = Tracing.current_loc := f in let _ = Tracing.next_loc := t in - let d = tf var getl sidel getg sideg prev_node edge d in - let _ = Tracing.current_loc := old_loc in - let _ = Tracing.next_loc := old_loc2 in - d + Fun.protect ~finally:(fun () -> + let _ = Tracing.current_loc := old_loc in + Tracing.next_loc := old_loc2 + ) (fun () -> + let d = tf var getl sidel getg sideg prev_node edge d in + d + ) let tf (v,c) (edges, u) getl sidel getg sideg = let pval = getl (u,c) in @@ -696,10 +699,15 @@ struct let old_context = !M.current_context in let _ = current_node := Some u in M.current_context := Some (Obj.repr c); - let d = tf (v,c) (e,u) getl sidel getg sideg in - let _ = current_node := old_node in - M.current_context := old_context; - d + Fun.protect ~finally:(fun () -> + let _ = current_node := old_node in + M.current_context := old_context + ) (fun () -> + let d = tf (v,c) (e,u) getl sidel getg sideg in + let _ = current_node := old_node in + M.current_context := old_context; + d + ) let system (v,c) = match v with From bae9516543929789e7d9e4e277cf610b9ad7dda6 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Tue, 28 Sep 2021 10:41:52 +0300 Subject: [PATCH 009/402] Fix first narrow iteration always aborting TD3 When widen iteration ends, everything is unchanged, so would always abort. Instead we disable aborting then, to force narrowing to happen at least once. --- src/solvers/td3.ml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/solvers/td3.ml b/src/solvers/td3.ml index 1df694c1c3..6ce0145192 100644 --- a/src/solvers/td3.ml +++ b/src/solvers/td3.ml @@ -117,7 +117,7 @@ module WP = HM.remove stable y; HM.mem called y || destabilize_vs y || b || was_stable && List.mem y vs ) w false - and solve x phase: bool = + and solve ?(abort=true) x phase: bool = if tracing then trace "sol2" "solve %a, called: %b, stable: %b\n" S.Var.pretty_trace x (HM.mem called x) (HM.mem stable x); init x; assert (S.system x <> None); @@ -128,7 +128,7 @@ module WP = let old = HM.find rho x in let l = HM.create 10 in let eval' = - if HM.mem dep x then ( + if HM.mem dep x && abort then ( let unasked_dep_x = ref (HM.find dep x) in let all_dep_x_unchanged = ref true in fun y -> @@ -181,7 +181,7 @@ module WP = (solve[@tailcall]) x Widen ) else if term && phase = Widen then ( HM.remove stable x; - (solve[@tailcall]) x Narrow + (solve[@tailcall]) ~abort:false x Narrow ) else if not space && (not term || phase = Narrow) then ( (* this makes e.g. nested loops precise, ex. tests/regression/34-localization/01-nested.c - if we do not remove wpoint, the inner loop head will stay a wpoint and widen the outer loop variable. *) HM.remove wpoint x; false From f88707f64f19fce18b00be00ec5d7e63e9167e54 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Tue, 28 Sep 2021 10:44:06 +0300 Subject: [PATCH 010/402] Fix aborting of branching loop bodies using destabilization front --- src/solvers/td3.ml | 34 +++++++++++++++++++++++++++++++--- 1 file changed, 31 insertions(+), 3 deletions(-) diff --git a/src/solvers/td3.ml b/src/solvers/td3.ml index 6ce0145192..03daac5741 100644 --- a/src/solvers/td3.ml +++ b/src/solvers/td3.ml @@ -82,6 +82,9 @@ module WP = let wpoint = data.wpoint in let stable = data.stable in + let destab_infl = HM.create 10 in + let destab_front = HM.create 10 in + let () = print_solver_stats := fun () -> Printf.printf "|rho|=%d\n|called|=%d\n|stable|=%d\n|infl|=%d\n|wpoint|=%d\n" (HM.length rho) (HM.length called) (HM.length stable) (HM.length infl) (HM.length wpoint); @@ -98,14 +101,23 @@ module WP = HM.replace dep x (VS.add y (try HM.find dep x with Not_found -> VS.empty)); in let add_sides y x = HM.replace sides y (VS.add x (try HM.find infl y with Not_found -> VS.empty)) in - let rec destabilize x = + let rec destabilize ?(front=true) x = if tracing then trace "sol2" "destabilize %a\n" S.Var.pretty_trace x; let w = HM.find_default infl x VS.empty in HM.replace infl x VS.empty; + (* HM.replace destab_infl x (VS.union w (HM.find_default destab_infl x VS.empty)); *) + if front then ( + VS.iter (fun y -> + HM.replace destab_front y () + ) w + ) + else ( + HM.replace destab_infl x (VS.union w (HM.find_default destab_infl x VS.empty)); + ); VS.iter (fun y -> (* TODO: remove from dep? *) HM.remove stable y; - if not (HM.mem called y) then destabilize y + if not (HM.mem called y) then destabilize ~front:false y ) w and destabilize_vs x = (* TODO remove? Only used for side_widen cycle. *) if tracing then trace "sol2" "destabilize_vs %a\n" S.Var.pretty_trace x; @@ -137,7 +149,7 @@ module WP = unasked_dep_x := VS.remove y !unasked_dep_x; if changed then all_dep_x_unchanged := false; - if VS.is_empty !unasked_dep_x && !all_dep_x_unchanged then + if VS.is_empty !unasked_dep_x && !all_dep_x_unchanged && not (HM.mem destab_front x) then (* must check front here, because each eval might change it for x *) raise AbortEq ); d @@ -172,11 +184,27 @@ module WP = update_var_event x old tmp; if tracing then trace "sol" "New Value:%a\n\n" S.Dom.pretty tmp; HM.replace rho x tmp; + if HM.mem destab_front x then ( + HM.remove destab_front x; + if HM.mem destab_infl x then ( + VS.iter (fun y -> + if tracing then trace "sol2" "pushing front from %a to %a\n" S.Var.pretty_trace x S.Var.pretty_trace y; + HM.replace destab_front y () + ) (HM.find destab_infl x) + ); + (* HM.remove destab_infl x *) + ); destabilize x; (* (solve[@tailcall]) x phase; *) ignore (solve x phase); true ) else ( + if HM.mem destab_front x then ( + HM.remove destab_front x; + if tracing then trace "sol2" "not pushing front from %a\n" S.Var.pretty_trace x; + (* don't push front here *) + (* HM.remove destab_infl x *) + ); if not (HM.mem stable x) then ( (solve[@tailcall]) x Widen ) else if term && phase = Widen then ( From 8594d03a77de3eaab98b3687bebcf50fd725adcf Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Tue, 28 Sep 2021 10:45:09 +0300 Subject: [PATCH 011/402] Add called_changed set to TD3 --- src/solvers/td3.ml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/solvers/td3.ml b/src/solvers/td3.ml index 03daac5741..91819d4d60 100644 --- a/src/solvers/td3.ml +++ b/src/solvers/td3.ml @@ -74,6 +74,7 @@ module WP = let space = GobConfig.get_bool "exp.solver.td3.space" in (* let cache = GobConfig.get_bool "exp.solver.td3.space_cache" in *) let called = HM.create 10 in + let called_changed = HM.create 10 in let infl = data.infl in let dep = HM.create 10 in @@ -170,6 +171,7 @@ module WP = if tracing then trace "sol" "Var: %a\n" S.Var.pretty_trace x ; if tracing then trace "sol" "Contrib:%a\n" S.Dom.pretty tmp; HM.remove called x; + HM.remove called_changed x; let tmp = if not wp then tmp else @@ -184,6 +186,7 @@ module WP = update_var_event x old tmp; if tracing then trace "sol" "New Value:%a\n\n" S.Dom.pretty tmp; HM.replace rho x tmp; + HM.replace called_changed x (); if HM.mem destab_front x then ( HM.remove destab_front x; if HM.mem destab_infl x then ( @@ -220,6 +223,7 @@ module WP = ) else if HM.mem called x then true + (* HM.mem called_changed x *) else false and eq x get set = From 6a317fd84aed101aa40db929db519b2d28fa93d0 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Mon, 27 Sep 2021 12:10:43 +0300 Subject: [PATCH 012/402] Add aborts counter to statistics --- src/maingoblint.ml | 2 +- src/solvers/generic.ml | 3 +++ src/solvers/td3.ml | 1 + src/util/goblintutil.ml | 1 + 4 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/maingoblint.ml b/src/maingoblint.ml index 18034e6d5e..29c871365b 100644 --- a/src/maingoblint.ml +++ b/src/maingoblint.ml @@ -282,7 +282,7 @@ let merge_preprocessed cpp_file_names = let do_stats () = if get_bool "printstats" then ( print_newline (); - ignore (Pretty.printf "vars = %d evals = %d \n" !Goblintutil.vars !Goblintutil.evals); + ignore (Pretty.printf "vars = %d evals = %d aborts = %d\n" !Goblintutil.vars !Goblintutil.evals !Goblintutil.aborts); print_newline (); Stats.print (Messages.get_out "timing" Legacy.stderr) "Timings:\n"; flush_all () diff --git a/src/solvers/generic.ml b/src/solvers/generic.ml index e6cd1eabbe..b5bdff2116 100644 --- a/src/solvers/generic.ml +++ b/src/solvers/generic.ml @@ -216,6 +216,9 @@ struct Goblintutil.evals := !Goblintutil.evals + 1; if (get_bool "dbg.solver-progress") then (incr stack_d; print_int !stack_d; flush stdout) + let abort_rhs_event x = + incr Goblintutil.aborts + let update_var_event x o n = if tracing then increase x; if full_trace || ((not (Dom.is_bot o)) && Option.is_some !max_var && Var.equal (Option.get !max_var) x) then begin diff --git a/src/solvers/td3.ml b/src/solvers/td3.ml index 91819d4d60..eb8b22b2ac 100644 --- a/src/solvers/td3.ml +++ b/src/solvers/td3.ml @@ -164,6 +164,7 @@ module WP = try eq x eval' (side x) with AbortEq -> + abort_rhs_event x; if tracing then trace "sol2" "eq aborted %a\n" S.Var.pretty_trace x; old in diff --git a/src/util/goblintutil.ml b/src/util/goblintutil.ml index c4963768f8..34447e06b5 100644 --- a/src/util/goblintutil.ml +++ b/src/util/goblintutil.ml @@ -346,6 +346,7 @@ let seconds_of_duration_string = let vars = ref 0 let evals = ref 0 +let aborts = ref 0 (* print GC statistics; taken from Cil.Stats.print which also includes timing; there's also Gc.print_stat, but it's in words instead of MB and more info than we want (also slower than quick_stat since it goes through the heap) *) let print_gc_quick_stat chn = From 982ddc3c1a385f9811ee632df692127d15455d8c Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Tue, 28 Sep 2021 10:57:03 +0300 Subject: [PATCH 013/402] Make TD3 solve changed tail recursive again --- src/solvers/td3.ml | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/src/solvers/td3.ml b/src/solvers/td3.ml index eb8b22b2ac..1109935c5f 100644 --- a/src/solvers/td3.ml +++ b/src/solvers/td3.ml @@ -130,7 +130,7 @@ module WP = HM.remove stable y; HM.mem called y || destabilize_vs y || b || was_stable && List.mem y vs ) w false - and solve ?(abort=true) x phase: bool = + and solve ?(abort=true) x phase (changed: bool): bool = if tracing then trace "sol2" "solve %a, called: %b, stable: %b\n" S.Var.pretty_trace x (HM.mem called x) (HM.mem stable x); init x; assert (S.system x <> None); @@ -199,9 +199,7 @@ module WP = (* HM.remove destab_infl x *) ); destabilize x; - (* (solve[@tailcall]) x phase; *) - ignore (solve x phase); - true + (solve[@tailcall]) x phase true ) else ( if HM.mem destab_front x then ( HM.remove destab_front x; @@ -210,23 +208,23 @@ module WP = (* HM.remove destab_infl x *) ); if not (HM.mem stable x) then ( - (solve[@tailcall]) x Widen + (solve[@tailcall]) x Widen changed ) else if term && phase = Widen then ( HM.remove stable x; - (solve[@tailcall]) ~abort:false x Narrow + (solve[@tailcall]) ~abort:false x Narrow changed ) else if not space && (not term || phase = Narrow) then ( (* this makes e.g. nested loops precise, ex. tests/regression/34-localization/01-nested.c - if we do not remove wpoint, the inner loop head will stay a wpoint and widen the outer loop variable. *) HM.remove wpoint x; - false + changed ) else - false + changed ) ) else if HM.mem called x then true (* HM.mem called_changed x *) else - false + changed and eq x get set = if tracing then trace "sol2" "eq %a\n" S.Var.pretty_trace x; eval_rhs_event x; @@ -236,7 +234,7 @@ module WP = and simple_solve l x y: S.d * bool = if tracing then trace "sol2" "simple_solve %a (rhs: %b)\n" S.Var.pretty_trace y (S.system y <> None); if S.system y = None then (init y; (HM.find rho y, true (* TODO: ??? *))) else - if HM.mem rho y || not space then (let changed = solve y Widen in (HM.find rho y, changed)) else + if HM.mem rho y || not space then (let changed = solve y Widen false in (HM.find rho y, changed)) else failwith "space abort unimplemented" and eval l x y: S.d * bool = if tracing then trace "sol2" "eval %a ## %a\n" S.Var.pretty_trace x S.Var.pretty_trace y; @@ -387,7 +385,7 @@ module WP = print_newline (); flush_all (); ); - List.iter (fun x -> ignore (solve x Widen)) unstable_vs; + List.iter (fun x -> ignore (solve x Widen false)) unstable_vs; solver (); ) in From c4cda6ac2182abf12cbc40d9de0b54b1e6b95b34 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Tue, 28 Sep 2021 10:57:29 +0300 Subject: [PATCH 014/402] Remove destab_infl after pushing destabilization front in TD3 --- src/solvers/td3.ml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/solvers/td3.ml b/src/solvers/td3.ml index 1109935c5f..03eb3ee968 100644 --- a/src/solvers/td3.ml +++ b/src/solvers/td3.ml @@ -196,7 +196,7 @@ module WP = HM.replace destab_front y () ) (HM.find destab_infl x) ); - (* HM.remove destab_infl x *) + HM.remove destab_infl x ); destabilize x; (solve[@tailcall]) x phase true @@ -205,7 +205,7 @@ module WP = HM.remove destab_front x; if tracing then trace "sol2" "not pushing front from %a\n" S.Var.pretty_trace x; (* don't push front here *) - (* HM.remove destab_infl x *) + HM.remove destab_infl x ); if not (HM.mem stable x) then ( (solve[@tailcall]) x Widen changed From 959206049aba777789239249fd4cb8ef08d1ed37 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Mon, 27 Sep 2021 11:55:51 +0300 Subject: [PATCH 015/402] Optimize TD3 dep to be just for destabilize --- src/solvers/td3.ml | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/solvers/td3.ml b/src/solvers/td3.ml index 03eb3ee968..53934d81a1 100644 --- a/src/solvers/td3.ml +++ b/src/solvers/td3.ml @@ -77,7 +77,6 @@ module WP = let called_changed = HM.create 10 in let infl = data.infl in - let dep = HM.create 10 in let sides = data.sides in let rho = data.rho in let wpoint = data.wpoint in @@ -85,6 +84,7 @@ module WP = let destab_infl = HM.create 10 in let destab_front = HM.create 10 in + let destab_dep = HM.create 10 in let () = print_solver_stats := fun () -> Printf.printf "|rho|=%d\n|called|=%d\n|stable|=%d\n|infl|=%d\n|wpoint|=%d\n" @@ -99,7 +99,7 @@ module WP = let add_infl y x = if tracing then trace "sol2" "add_infl %a %a\n" S.Var.pretty_trace y S.Var.pretty_trace x; HM.replace infl y (VS.add x (try HM.find infl y with Not_found -> VS.empty)); - HM.replace dep x (VS.add y (try HM.find dep x with Not_found -> VS.empty)); + (* HM.replace dep x (VS.add y (try HM.find dep x with Not_found -> VS.empty)); *) in let add_sides y x = HM.replace sides y (VS.add x (try HM.find infl y with Not_found -> VS.empty)) in let rec destabilize ?(front=true) x = @@ -114,6 +114,9 @@ module WP = ) else ( HM.replace destab_infl x (VS.union w (HM.find_default destab_infl x VS.empty)); + VS.iter (fun y -> + HM.replace destab_dep y (VS.add x (try HM.find destab_dep y with Not_found -> VS.empty)) + ) w ); VS.iter (fun y -> (* TODO: remove from dep? *) @@ -141,8 +144,8 @@ module WP = let old = HM.find rho x in let l = HM.create 10 in let eval' = - if HM.mem dep x && abort then ( - let unasked_dep_x = ref (HM.find dep x) in + if HM.mem destab_dep x && abort then ( + let unasked_dep_x = ref (HM.find destab_dep x) in let all_dep_x_unchanged = ref true in fun y -> let (d, changed) = eval l x y in @@ -197,6 +200,7 @@ module WP = ) (HM.find destab_infl x) ); HM.remove destab_infl x + (* TODO: remove from destab_dep? *) ); destabilize x; (solve[@tailcall]) x phase true @@ -206,6 +210,7 @@ module WP = if tracing then trace "sol2" "not pushing front from %a\n" S.Var.pretty_trace x; (* don't push front here *) HM.remove destab_infl x + (* TODO: remove from destab_dep? *) ); if not (HM.mem stable x) then ( (solve[@tailcall]) x Widen changed From 27aa497a800ec8f6bc3e36c314f8a88191aa4412 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Mon, 27 Sep 2021 12:03:44 +0300 Subject: [PATCH 016/402] Optimize TD3 by removing destab_dep after use --- src/solvers/td3.ml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/solvers/td3.ml b/src/solvers/td3.ml index 53934d81a1..7ef39f24d3 100644 --- a/src/solvers/td3.ml +++ b/src/solvers/td3.ml @@ -169,6 +169,7 @@ module WP = with AbortEq -> abort_rhs_event x; if tracing then trace "sol2" "eq aborted %a\n" S.Var.pretty_trace x; + HM.remove destab_dep x; (* TODO: safe to remove here? doesn't prevent some aborts? *) old in (* let tmp = if GobConfig.get_bool "ana.opt.hashcons" then S.Dom.join (S.Dom.bot ()) tmp else tmp in (* Call hashcons via dummy join so that the tag of the rhs value is up to date. Otherwise we might get the same value as old, but still with a different tag (because no lattice operation was called after a change), and since Printable.HConsed.equal just looks at the tag, we would uneccessarily destabilize below. Seems like this does not happen. *) *) @@ -200,7 +201,6 @@ module WP = ) (HM.find destab_infl x) ); HM.remove destab_infl x - (* TODO: remove from destab_dep? *) ); destabilize x; (solve[@tailcall]) x phase true @@ -210,7 +210,6 @@ module WP = if tracing then trace "sol2" "not pushing front from %a\n" S.Var.pretty_trace x; (* don't push front here *) HM.remove destab_infl x - (* TODO: remove from destab_dep? *) ); if not (HM.mem stable x) then ( (solve[@tailcall]) x Widen changed From 64457918b09453fb5d24f6f7ee9da4d18733a3bf Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Mon, 27 Sep 2021 12:30:47 +0300 Subject: [PATCH 017/402] Optimize TD3 called aborting --- src/solvers/td3.ml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/solvers/td3.ml b/src/solvers/td3.ml index 7ef39f24d3..81c019b9e6 100644 --- a/src/solvers/td3.ml +++ b/src/solvers/td3.ml @@ -225,8 +225,8 @@ module WP = ) ) else if HM.mem called x then - true - (* HM.mem called_changed x *) + (* true *) + changed || HM.mem called_changed x else changed and eq x get set = From 38971a106a36da58c976c766a176bff064cc84a9 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Mon, 27 Sep 2021 12:35:00 +0300 Subject: [PATCH 018/402] Remove duplicate current node and context reset in FromSpec --- src/framework/constraints.ml | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/src/framework/constraints.ml b/src/framework/constraints.ml index d38836c239..e6b316853b 100644 --- a/src/framework/constraints.ml +++ b/src/framework/constraints.ml @@ -679,10 +679,10 @@ struct let tf var getl sidel getg sideg prev_node (_,edge) d (f,t) = let old_loc = !Tracing.current_loc in let old_loc2 = !Tracing.next_loc in - let _ = Tracing.current_loc := f in - let _ = Tracing.next_loc := t in + Tracing.current_loc := f; + Tracing.next_loc := t; Fun.protect ~finally:(fun () -> - let _ = Tracing.current_loc := old_loc in + Tracing.current_loc := old_loc; Tracing.next_loc := old_loc2 ) (fun () -> let d = tf var getl sidel getg sideg prev_node edge d in @@ -697,15 +697,13 @@ struct let tf (v,c) (e,u) getl sidel getg sideg = let old_node = !current_node in let old_context = !M.current_context in - let _ = current_node := Some u in + current_node := Some u; M.current_context := Some (Obj.repr c); Fun.protect ~finally:(fun () -> - let _ = current_node := old_node in + current_node := old_node; M.current_context := old_context ) (fun () -> let d = tf (v,c) (e,u) getl sidel getg sideg in - let _ = current_node := old_node in - M.current_context := old_context; d ) From 88d12dd7d7e49315d2965eebcfea4876537f1114 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Tue, 28 Sep 2021 11:00:19 +0300 Subject: [PATCH 019/402] Remove old comments in TD3 --- src/solvers/td3.ml | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/solvers/td3.ml b/src/solvers/td3.ml index 81c019b9e6..241f8c8271 100644 --- a/src/solvers/td3.ml +++ b/src/solvers/td3.ml @@ -99,14 +99,12 @@ module WP = let add_infl y x = if tracing then trace "sol2" "add_infl %a %a\n" S.Var.pretty_trace y S.Var.pretty_trace x; HM.replace infl y (VS.add x (try HM.find infl y with Not_found -> VS.empty)); - (* HM.replace dep x (VS.add y (try HM.find dep x with Not_found -> VS.empty)); *) in let add_sides y x = HM.replace sides y (VS.add x (try HM.find infl y with Not_found -> VS.empty)) in let rec destabilize ?(front=true) x = if tracing then trace "sol2" "destabilize %a\n" S.Var.pretty_trace x; let w = HM.find_default infl x VS.empty in HM.replace infl x VS.empty; - (* HM.replace destab_infl x (VS.union w (HM.find_default destab_infl x VS.empty)); *) if front then ( VS.iter (fun y -> HM.replace destab_front y () @@ -119,7 +117,6 @@ module WP = ) w ); VS.iter (fun y -> - (* TODO: remove from dep? *) HM.remove stable y; if not (HM.mem called y) then destabilize ~front:false y ) w @@ -128,7 +125,6 @@ module WP = let w = HM.find_default infl x VS.empty in HM.replace infl x VS.empty; VS.fold (fun y b -> - (* TODO: remove from dep? *) let was_stable = HM.mem stable y in HM.remove stable y; HM.mem called y || destabilize_vs y || b || was_stable && List.mem y vs @@ -225,7 +221,6 @@ module WP = ) ) else if HM.mem called x then - (* true *) changed || HM.mem called_changed x else changed From 9a23c2e29712ab2f055d8687350333d856458d73 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 29 Sep 2021 11:11:00 +0300 Subject: [PATCH 020/402] Disable hardcoded TD3 globals restart --- src/solvers/td3.ml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/solvers/td3.ml b/src/solvers/td3.ml index bbf2846e88..0a40c5cef9 100644 --- a/src/solvers/td3.ml +++ b/src/solvers/td3.ml @@ -332,7 +332,7 @@ module WP = in solver (); - Printf.printf "Restarting globals\n"; + (* Printf.printf "Restarting globals\n"; if tracing then trace "sol2" "Restarting globals\n"; HM.iter (fun x _ -> (* TODO: hack to identify globals *) @@ -349,7 +349,7 @@ module WP = List.iter set_start st; (* TODO: necessary? *) (* List.iter init vs; *) - solver (); + solver (); *) (* Before we solved all unstable vars in rho with a rhs in a loop. This is unneeded overhead since it also solved unreachable vars (reachability only removes those from rho further down). *) (* After termination, only those variables are stable which are * - reachable from any of the queried variables vs, or From e8919b845e2c2f5b6a792f0e249b8c4c00435424 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 29 Sep 2021 11:11:34 +0300 Subject: [PATCH 021/402] Add incremental test script --- scripts/test-incremental.sh | 18 ++++++++++++++++++ tests/incremental/01-global.c | 16 ++++++++++++++++ tests/incremental/01-global.json | 3 +++ tests/incremental/01-global.patch | 20 ++++++++++++++++++++ 4 files changed, 57 insertions(+) create mode 100755 scripts/test-incremental.sh create mode 100644 tests/incremental/01-global.c create mode 100644 tests/incremental/01-global.json create mode 100644 tests/incremental/01-global.patch diff --git a/scripts/test-incremental.sh b/scripts/test-incremental.sh new file mode 100755 index 0000000000..f1bbf92454 --- /dev/null +++ b/scripts/test-incremental.sh @@ -0,0 +1,18 @@ +#!/usr/bin/env bash + +test=$1 + +base=./tests/incremental/ +source=$base$test.c +conf=$base$test.json +patch=$base$test.patch + +args="--enable dbg.debug --enable printstats -v" + +./goblint --conf $conf $args --enable incremental.save $source &> $base$test.before.log + +patch -b $source $patch + +./goblint --conf $conf $args --enable incremental.load $source &> $base$test.after.log + +patch -b -R $source $patch diff --git a/tests/incremental/01-global.c b/tests/incremental/01-global.c new file mode 100644 index 0000000000..d21524107f --- /dev/null +++ b/tests/incremental/01-global.c @@ -0,0 +1,16 @@ +#include +#include + +int g = 1; + +void* t_fun(void *arg) { + return NULL; +} + +int main() { + pthread_t id; + pthread_create(&id, NULL, t_fun, NULL); // just go multithreaded + + assert(g == 1); + return 0; +} \ No newline at end of file diff --git a/tests/incremental/01-global.json b/tests/incremental/01-global.json new file mode 100644 index 0000000000..0e0dcd235c --- /dev/null +++ b/tests/incremental/01-global.json @@ -0,0 +1,3 @@ +{ + +} \ No newline at end of file diff --git a/tests/incremental/01-global.patch b/tests/incremental/01-global.patch new file mode 100644 index 0000000000..649c2b0e14 --- /dev/null +++ b/tests/incremental/01-global.patch @@ -0,0 +1,20 @@ +--- tests/incremental/01-global.c 2021-09-29 11:07:05.155250278 +0300 ++++ "tests/incremental/01-global copy.c" 2021-09-29 11:07:21.507273052 +0300 +@@ -1,7 +1,7 @@ + #include + #include + +-int g = 1; ++int g = 2; + + void* t_fun(void *arg) { + return NULL; +@@ -11,6 +11,6 @@ + pthread_t id; + pthread_create(&id, NULL, t_fun, NULL); // just go multithreaded + +- assert(g == 1); ++ assert(g == 2); + return 0; + } +\ No newline at end of file From 74659b8dd9381a8477d64854bba389174f06e344 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 29 Sep 2021 11:12:33 +0300 Subject: [PATCH 022/402] Add incremental files to .gitignore --- .gitignore | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.gitignore b/.gitignore index 58574959ef..f2a1840fe6 100644 --- a/.gitignore +++ b/.gitignore @@ -64,3 +64,9 @@ runtime/* # perf perf.data* + +# incremental analysis +incremental_data/ + +# test-incremental.sh +*.log From 50f4d0440aa0c54c5a1650b448e5fa3e832a97aa Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 29 Sep 2021 12:23:11 +0300 Subject: [PATCH 023/402] Add from-scratch after output to test-incremental.sh for comparison --- scripts/test-incremental.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/scripts/test-incremental.sh b/scripts/test-incremental.sh index f1bbf92454..5da8c139b5 100755 --- a/scripts/test-incremental.sh +++ b/scripts/test-incremental.sh @@ -13,6 +13,7 @@ args="--enable dbg.debug --enable printstats -v" patch -b $source $patch -./goblint --conf $conf $args --enable incremental.load $source &> $base$test.after.log +./goblint --conf $conf $args --enable incremental.load $source &> $base$test.after.incr.log +./goblint --conf $conf $args $source &> $base$test.after.scratch.log patch -b -R $source $patch From 33c17ed3acece8776b2a55433dc320208b2b08dd Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 29 Sep 2021 12:23:57 +0300 Subject: [PATCH 024/402] Replace hardcoded TD3 global restart with global restart during incremental --- src/solvers/td3.ml | 77 ++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 65 insertions(+), 12 deletions(-) diff --git a/src/solvers/td3.ml b/src/solvers/td3.ml index 0a40c5cef9..0fbfd20bea 100644 --- a/src/solvers/td3.ml +++ b/src/solvers/td3.ml @@ -29,7 +29,9 @@ module WP = mutable sides: VS.t HM.t; mutable rho: S.Dom.t HM.t; mutable wpoint: unit HM.t; - mutable stable: unit HM.t + mutable stable: unit HM.t; + mutable side_dep: VS.t HM.t; + mutable side_infl: VS.t HM.t; } let create_empty_data () = { @@ -38,17 +40,20 @@ module WP = sides = HM.create 10; rho = HM.create 10; wpoint = HM.create 10; - stable = HM.create 10 + stable = HM.create 10; + side_dep = HM.create 10; + side_infl = HM.create 10; } + (* TODO: unused *) let clear_data data = HM.clear data.infl; HM.clear data.stable let print_data data str = if GobConfig.get_bool "dbg.verbose" then - Printf.printf "%s:\n|rho|=%d\n|stable|=%d\n|infl|=%d\n|wpoint|=%d\n" - str (HM.length data.rho) (HM.length data.stable) (HM.length data.infl) (HM.length data.wpoint) + Printf.printf "%s:\n|rho|=%d\n|stable|=%d\n|infl|=%d\n|wpoint|=%d\n|side_dep|=%d\n|side_infl|=%d\n" + str (HM.length data.rho) (HM.length data.stable) (HM.length data.infl) (HM.length data.wpoint) (HM.length data.side_dep) (HM.length data.side_infl) let exists_key f hm = HM.fold (fun k _ a -> a || f k) hm false @@ -75,11 +80,12 @@ module WP = let wpoint = data.wpoint in let stable = data.stable in - let side_dep = HM.create 10 in + let side_dep = data.side_dep in + let side_infl = data.side_infl in let () = print_solver_stats := fun () -> - Printf.printf "|rho|=%d\n|called|=%d\n|stable|=%d\n|infl|=%d\n|wpoint|=%d\n" - (HM.length rho) (HM.length called) (HM.length stable) (HM.length infl) (HM.length wpoint); + Printf.printf "|rho|=%d\n|called|=%d\n|stable|=%d\n|infl|=%d\n|wpoint|=%d\n|side_dep|=%d\n|side_infl|=%d\n" + (HM.length rho) (HM.length called) (HM.length stable) (HM.length infl) (HM.length wpoint) (HM.length side_dep) (HM.length side_infl); print_context_stats rho in @@ -100,14 +106,14 @@ module WP = HM.remove stable y; if not (HM.mem called y) then destabilize y ) w - and destabilize_side x = + (* and destabilize_side x = if tracing then trace "sol2" "destabilize_side %a\n" S.Var.pretty_trace x; let w = HM.find_default side_dep x VS.empty in HM.replace side_dep x VS.empty; VS.iter (fun y -> HM.remove stable y; if not (HM.mem called y) then destabilize y - ) w + ) w *) and destabilize_vs x = (* TODO remove? Only used for side_widen cycle. *) if tracing then trace "sol2" "destabilize_vs %a\n" S.Var.pretty_trace x; let w = HM.find_default infl x VS.empty in @@ -190,7 +196,9 @@ module WP = ); assert (S.system y = None); init y; + (* TODO: only add side_dep, side_infl at reachability/verify *) HM.replace side_dep y (VS.add x (try HM.find side_dep y with Not_found -> VS.empty)); + HM.replace side_infl x (VS.add y (try HM.find side_infl x with Not_found -> VS.empty)); if side_widen = "unstable_self" then add_infl x y; let op = if HM.mem wpoint y then fun a b -> @@ -251,6 +259,51 @@ module WP = if GobConfig.get_bool "incremental.load" then ( let c = S.increment.changes in List.(Printf.printf "change_info = { unchanged = %d; changed = %d; added = %d; removed = %d }\n" (length c.unchanged) (length c.changed) (length c.added) (length c.removed)); + + (* destabilize which restarts side-effected vars *) + let rec destabilize_with_side x = + if tracing then trace "sol2" "destabilize_with_side %a\n" S.Var.pretty_trace x; + + (* is side-effected var (global/function entry)? *) + let w = HM.find_default side_dep x VS.empty in + HM.replace side_dep x VS.empty; + + if not (VS.is_empty w) then ( + (* restart side-effected var *) + if tracing then trace "sol2" "Restarting to bot %a\n" S.Var.pretty_trace x; + ignore (Pretty.printf "Restarting to bot %a\n" S.Var.pretty_trace x); + HM.replace rho x (S.Dom.bot ()); + (* HM.remove rho x; *) + HM.remove wpoint x; (* otherwise gets immediately widened during resolve *) + HM.remove sides x; (* just in case *) + + (* destabilize side dep to redo side effects *) + VS.iter (fun y -> + if tracing then trace "sol2" "destabilize_with_side %a side_dep %a\n" S.Var.pretty_trace x S.Var.pretty_trace y; + HM.remove stable y; + destabilize_with_side y + ) w + ); + + (* destabilize eval infl *) + let w = HM.find_default infl x VS.empty in + HM.replace infl x VS.empty; + VS.iter (fun y -> + if tracing then trace "sol2" "destabilize_with_side %a infl %a\n" S.Var.pretty_trace x S.Var.pretty_trace y; + HM.remove stable y; + destabilize_with_side y + ) w; + + (* destabilize side infl *) + let w = HM.find_default side_infl x VS.empty in + HM.replace side_infl x VS.empty; + VS.iter (fun y -> + if tracing then trace "sol2" "destabilize_with_side %a side_infl %a\n" S.Var.pretty_trace x S.Var.pretty_trace y; + HM.remove stable y; + destabilize_with_side y + ) w + in + (* If a global changes because of some assignment inside a function, we reanalyze, * but if it changes because of a different global initializer, then * if not exp.earlyglobs: the contexts of start functions will change, we don't find the value in rho and reanalyze; @@ -266,7 +319,7 @@ module WP = () else ( ignore @@ Pretty.printf "Function %a has changed start state: %a\n" S.Var.pretty_trace v S.Dom.pretty_diff (d, d'); - destabilize v + destabilize_with_side v ) | None -> ignore @@ Pretty.printf "New start function %a not found in old list!\n" S.Var.pretty_trace v ) st; @@ -286,7 +339,7 @@ module WP = List.iter (fun a -> print_endline ("Obsolete function: " ^ a.svar.vname)) obsolete_funs; (* Actually destabilize all nodes contained in changed functions. TODO only destabilize fun_... nodes *) - HM.iter (fun k v -> if Set.mem (S.Var.var_id k) obsolete then destabilize k) stable; (* TODO: don't use string-based nodes *) + HM.iter (fun k v -> if Set.mem (S.Var.var_id k) obsolete then destabilize_with_side k) stable; (* TODO: don't use string-based nodes *) (* We remove all unknowns for program points in changed or removed functions from rho, stable, infl and wpoint *) (* TODO: don't use string-based nodes, make marked_for_deletion of type unit (Hashtbl.Make (Node)).t *) @@ -430,7 +483,7 @@ module WP = print_newline (); ); - {st; infl; sides; rho; wpoint; stable} + {st; infl; sides; rho; wpoint; stable; side_dep; side_infl} let solve box st vs = let reuse_stable = GobConfig.get_bool "incremental.stable" in From 44a4d1a771d9780c79da5b585b48451c4fa8a1e6 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 29 Sep 2021 12:26:42 +0300 Subject: [PATCH 025/402] Delete obsolete side_dep and side_infl in TD3 --- src/solvers/td3.ml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/solvers/td3.ml b/src/solvers/td3.ml index 0fbfd20bea..b4d5fb3b7b 100644 --- a/src/solvers/td3.ml +++ b/src/solvers/td3.ml @@ -360,6 +360,8 @@ module WP = delete_marked infl; delete_marked wpoint; delete_marked stable; + delete_marked side_dep; + delete_marked side_infl; print_data data "Data after clean-up" ); From ec4bc1dc2e4b2c65e76bfaf0b148097318b7dd69 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 29 Sep 2021 13:56:25 +0300 Subject: [PATCH 026/402] Remove variables from TD3 side_dep and side_infl Instead of replacing them with empty sets. --- src/solvers/td3.ml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/solvers/td3.ml b/src/solvers/td3.ml index b4d5fb3b7b..d6a4609cc8 100644 --- a/src/solvers/td3.ml +++ b/src/solvers/td3.ml @@ -266,7 +266,7 @@ module WP = (* is side-effected var (global/function entry)? *) let w = HM.find_default side_dep x VS.empty in - HM.replace side_dep x VS.empty; + HM.remove side_dep x; if not (VS.is_empty w) then ( (* restart side-effected var *) @@ -296,7 +296,7 @@ module WP = (* destabilize side infl *) let w = HM.find_default side_infl x VS.empty in - HM.replace side_infl x VS.empty; + HM.remove side_infl x; VS.iter (fun y -> if tracing then trace "sol2" "destabilize_with_side %a side_infl %a\n" S.Var.pretty_trace x S.Var.pretty_trace y; HM.remove stable y; From faaaa6fdc9422400877ca34d7b059798d2e339ef Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 29 Sep 2021 13:59:10 +0300 Subject: [PATCH 027/402] Improve TD3 side_dep and side_infl by collecting during reachability This avoids unnecessary work during solving. It also prevents spurious infls that disappear during narrowing. --- src/solvers/td3.ml | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/src/solvers/td3.ml b/src/solvers/td3.ml index d6a4609cc8..597a9db042 100644 --- a/src/solvers/td3.ml +++ b/src/solvers/td3.ml @@ -196,9 +196,6 @@ module WP = ); assert (S.system y = None); init y; - (* TODO: only add side_dep, side_infl at reachability/verify *) - HM.replace side_dep y (VS.add x (try HM.find side_dep y with Not_found -> VS.empty)); - HM.replace side_infl x (VS.add y (try HM.find side_infl x with Not_found -> VS.empty)); if side_widen = "unstable_self" then add_infl x y; let op = if HM.mem wpoint y then fun a b -> @@ -459,6 +456,10 @@ module WP = if tracing then trace "cache" "#caches: %d, max: %d, avg: %.2f\n" (List.length !cache_sizes) (List.max !cache_sizes) (avg !cache_sizes); ); + (* reachability will populate these tables for incremental global restarting *) + HM.clear side_dep; + HM.clear side_infl; + let reachability xs = let reachable = HM.create (HM.length rho) in let rec one_var x = @@ -466,10 +467,14 @@ module WP = HM.replace reachable x (); match S.system x with | None -> () - | Some x -> one_constraint x + | Some f -> one_constraint x f ) - and one_constraint f = - ignore (f (fun x -> one_var x; try HM.find rho x with Not_found -> ignore @@ Pretty.printf "reachability: one_constraint: could not find variable %a\n" S.Var.pretty_trace x; S.Dom.bot ()) (fun x _ -> one_var x)) + and one_side x y _ = + one_var y; + HM.replace side_dep y (VS.add x (try HM.find side_dep y with Not_found -> VS.empty)); + HM.replace side_infl x (VS.add y (try HM.find side_infl x with Not_found -> VS.empty)); + and one_constraint x f = + ignore (f (fun x -> one_var x; try HM.find rho x with Not_found -> ignore @@ Pretty.printf "reachability: one_constraint: could not find variable %a\n" S.Var.pretty_trace x; S.Dom.bot ()) (one_side x)) in List.iter one_var xs; HM.iter (fun x v -> if not (HM.mem reachable x) then HM.remove rho x) rho; From 319a9c2cbf4845d5b8d4a2e617d9d52050257ba5 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 29 Sep 2021 14:03:54 +0300 Subject: [PATCH 028/402] Add restart_only_globals to TD3 --- src/solvers/td3.ml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/solvers/td3.ml b/src/solvers/td3.ml index 597a9db042..e284109740 100644 --- a/src/solvers/td3.ml +++ b/src/solvers/td3.ml @@ -82,6 +82,9 @@ module WP = let side_dep = data.side_dep in let side_infl = data.side_infl in + (* If true, incremental side-effected var restart will only restart destabilized globals (using hack). + if false, it will restart all destabilized side-effected vars. *) + let restart_only_globals = false in let () = print_solver_stats := fun () -> Printf.printf "|rho|=%d\n|called|=%d\n|stable|=%d\n|infl|=%d\n|wpoint|=%d\n|side_dep|=%d\n|side_infl|=%d\n" @@ -265,7 +268,7 @@ module WP = let w = HM.find_default side_dep x VS.empty in HM.remove side_dep x; - if not (VS.is_empty w) then ( + if not (VS.is_empty w) && (not restart_only_globals || Node.equal (S.Var.node x) (Function Cil.dummyFunDec)) then ( (* restart side-effected var *) if tracing then trace "sol2" "Restarting to bot %a\n" S.Var.pretty_trace x; ignore (Pretty.printf "Restarting to bot %a\n" S.Var.pretty_trace x); From 3a21c52e2de73b53b0d4ce62f1986406d854f0e3 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 29 Sep 2021 14:05:15 +0300 Subject: [PATCH 029/402] Add expected outcome to 01-global incremental test --- tests/incremental/01-global.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/incremental/01-global.c b/tests/incremental/01-global.c index d21524107f..21438146fa 100644 --- a/tests/incremental/01-global.c +++ b/tests/incremental/01-global.c @@ -11,6 +11,6 @@ int main() { pthread_t id; pthread_create(&id, NULL, t_fun, NULL); // just go multithreaded - assert(g == 1); + assert(g == 1); // success before, success after return 0; } \ No newline at end of file From 675d66d8f055ea2e3e013205718886c9c5ca2632 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 29 Sep 2021 14:12:16 +0300 Subject: [PATCH 030/402] Add incremental tests for removing, changing and adding side effect --- tests/incremental/02-global-remove.c | 17 +++++++++++++++++ tests/incremental/02-global-remove.json | 3 +++ tests/incremental/02-global-remove.patch | 10 ++++++++++ tests/incremental/03-global-change.c | 19 +++++++++++++++++++ tests/incremental/03-global-change.json | 7 +++++++ tests/incremental/03-global-change.patch | 11 +++++++++++ tests/incremental/04-global-add.c | 16 ++++++++++++++++ tests/incremental/04-global-add.json | 3 +++ tests/incremental/04-global-add.patch | 10 ++++++++++ 9 files changed, 96 insertions(+) create mode 100644 tests/incremental/02-global-remove.c create mode 100644 tests/incremental/02-global-remove.json create mode 100644 tests/incremental/02-global-remove.patch create mode 100644 tests/incremental/03-global-change.c create mode 100644 tests/incremental/03-global-change.json create mode 100644 tests/incremental/03-global-change.patch create mode 100644 tests/incremental/04-global-add.c create mode 100644 tests/incremental/04-global-add.json create mode 100644 tests/incremental/04-global-add.patch diff --git a/tests/incremental/02-global-remove.c b/tests/incremental/02-global-remove.c new file mode 100644 index 0000000000..baa4706154 --- /dev/null +++ b/tests/incremental/02-global-remove.c @@ -0,0 +1,17 @@ +#include +#include + +int g = 1; + +void* t_fun(void *arg) { + g = 2; + return NULL; +} + +int main() { + pthread_t id; + pthread_create(&id, NULL, t_fun, NULL); // just go multithreaded + + assert(g == 1); // unknown before, success after + return 0; +} \ No newline at end of file diff --git a/tests/incremental/02-global-remove.json b/tests/incremental/02-global-remove.json new file mode 100644 index 0000000000..0e0dcd235c --- /dev/null +++ b/tests/incremental/02-global-remove.json @@ -0,0 +1,3 @@ +{ + +} \ No newline at end of file diff --git a/tests/incremental/02-global-remove.patch b/tests/incremental/02-global-remove.patch new file mode 100644 index 0000000000..2f3c81079d --- /dev/null +++ b/tests/incremental/02-global-remove.patch @@ -0,0 +1,10 @@ +--- tests/incremental/02-global-remove.c 2021-09-29 14:05:58.951606435 +0300 ++++ "tests/incremental/02-global-remove copy.c" 2021-09-29 14:06:08.619662600 +0300 +@@ -4,7 +4,6 @@ + int g = 1; + + void* t_fun(void *arg) { +- g = 2; + return NULL; + } + diff --git a/tests/incremental/03-global-change.c b/tests/incremental/03-global-change.c new file mode 100644 index 0000000000..9d63c62b86 --- /dev/null +++ b/tests/incremental/03-global-change.c @@ -0,0 +1,19 @@ +#include +#include + +int g = 1; + +void* t_fun(void *arg) { + g = 2; + return NULL; +} + +int main() { + pthread_t id; + pthread_create(&id, NULL, t_fun, NULL); // just go multithreaded + + assert(g == 1); // unknown before, unknown after + assert(g == 2); // unknown before, fail after + assert(g == 0); // fail before, unknown after + return 0; +} \ No newline at end of file diff --git a/tests/incremental/03-global-change.json b/tests/incremental/03-global-change.json new file mode 100644 index 0000000000..5be265f269 --- /dev/null +++ b/tests/incremental/03-global-change.json @@ -0,0 +1,7 @@ +{ + "ana": { + "int": { + "interval": true + } + } +} \ No newline at end of file diff --git a/tests/incremental/03-global-change.patch b/tests/incremental/03-global-change.patch new file mode 100644 index 0000000000..db7d935591 --- /dev/null +++ b/tests/incremental/03-global-change.patch @@ -0,0 +1,11 @@ +--- tests/incremental/03-global-change.c 2021-09-29 14:09:02.080670467 +0300 ++++ "tests/incremental/03-global-change copy.c" 2021-09-29 14:09:11.456724953 +0300 +@@ -4,7 +4,7 @@ + int g = 1; + + void* t_fun(void *arg) { +- g = 2; ++ g = 0; + return NULL; + } + diff --git a/tests/incremental/04-global-add.c b/tests/incremental/04-global-add.c new file mode 100644 index 0000000000..fa7055149a --- /dev/null +++ b/tests/incremental/04-global-add.c @@ -0,0 +1,16 @@ +#include +#include + +int g = 1; + +void* t_fun(void *arg) { + return NULL; +} + +int main() { + pthread_t id; + pthread_create(&id, NULL, t_fun, NULL); // just go multithreaded + + assert(g == 1); // success before, unknown after + return 0; +} \ No newline at end of file diff --git a/tests/incremental/04-global-add.json b/tests/incremental/04-global-add.json new file mode 100644 index 0000000000..0e0dcd235c --- /dev/null +++ b/tests/incremental/04-global-add.json @@ -0,0 +1,3 @@ +{ + +} \ No newline at end of file diff --git a/tests/incremental/04-global-add.patch b/tests/incremental/04-global-add.patch new file mode 100644 index 0000000000..499603b716 --- /dev/null +++ b/tests/incremental/04-global-add.patch @@ -0,0 +1,10 @@ +--- tests/incremental/04-global-add.c 2021-09-29 14:11:10.085414395 +0300 ++++ "tests/incremental/04-global-add copy.c" 2021-09-29 14:11:15.785447525 +0300 +@@ -4,6 +4,7 @@ + int g = 1; + + void* t_fun(void *arg) { ++ g = 2; + return NULL; + } + From 6dda3dd2895651abea08b31e6d3999d4e92e7eed Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 29 Sep 2021 14:27:22 +0300 Subject: [PATCH 031/402] Add example usage of test-incremental.sh --- scripts/test-incremental.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/scripts/test-incremental.sh b/scripts/test-incremental.sh index 5da8c139b5..5b4de6ea23 100755 --- a/scripts/test-incremental.sh +++ b/scripts/test-incremental.sh @@ -1,5 +1,7 @@ #!/usr/bin/env bash +# Example: ./scripts/test-incremental.sh 01-global + test=$1 base=./tests/incremental/ From 436afff2fa5848b46f48ad50904e2217bb7bf6dc Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 29 Sep 2021 14:28:57 +0300 Subject: [PATCH 032/402] Fix 01-global incremental test patch --- tests/incremental/01-global.patch | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/incremental/01-global.patch b/tests/incremental/01-global.patch index 649c2b0e14..d722d254e0 100644 --- a/tests/incremental/01-global.patch +++ b/tests/incremental/01-global.patch @@ -13,8 +13,8 @@ pthread_t id; pthread_create(&id, NULL, t_fun, NULL); // just go multithreaded -- assert(g == 1); -+ assert(g == 2); +- assert(g == 1); // success before, success after ++ assert(g == 2); // success before, success after return 0; } \ No newline at end of file From 227b5a5706e9fb52f383f332e9108057e281d908 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 29 Sep 2021 14:29:35 +0300 Subject: [PATCH 033/402] Add *.rej to .gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index f2a1840fe6..b78a710c37 100644 --- a/.gitignore +++ b/.gitignore @@ -53,6 +53,7 @@ goblint.bc.js # Files generated by merge tools after conflicts *.orig +*.rej sv-comp/goblint.zip From ac65f2d25d51941845eaa3458821203e00360228 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 29 Sep 2021 14:29:43 +0300 Subject: [PATCH 034/402] Remove unused clear_data in TD3 --- src/solvers/td3.ml | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/solvers/td3.ml b/src/solvers/td3.ml index e284109740..017dadd34c 100644 --- a/src/solvers/td3.ml +++ b/src/solvers/td3.ml @@ -45,11 +45,6 @@ module WP = side_infl = HM.create 10; } - (* TODO: unused *) - let clear_data data = - HM.clear data.infl; - HM.clear data.stable - let print_data data str = if GobConfig.get_bool "dbg.verbose" then Printf.printf "%s:\n|rho|=%d\n|stable|=%d\n|infl|=%d\n|wpoint|=%d\n|side_dep|=%d\n|side_infl|=%d\n" From da1bcac53cc5618ce4832bdfafae1898ffd93a28 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 29 Sep 2021 14:30:35 +0300 Subject: [PATCH 035/402] Remove old commented out destabilize_side code from TD3 --- src/solvers/td3.ml | 27 --------------------------- 1 file changed, 27 deletions(-) diff --git a/src/solvers/td3.ml b/src/solvers/td3.ml index 017dadd34c..449baa68cc 100644 --- a/src/solvers/td3.ml +++ b/src/solvers/td3.ml @@ -104,14 +104,6 @@ module WP = HM.remove stable y; if not (HM.mem called y) then destabilize y ) w - (* and destabilize_side x = - if tracing then trace "sol2" "destabilize_side %a\n" S.Var.pretty_trace x; - let w = HM.find_default side_dep x VS.empty in - HM.replace side_dep x VS.empty; - VS.iter (fun y -> - HM.remove stable y; - if not (HM.mem called y) then destabilize y - ) w *) and destabilize_vs x = (* TODO remove? Only used for side_widen cycle. *) if tracing then trace "sol2" "destabilize_vs %a\n" S.Var.pretty_trace x; let w = HM.find_default infl x VS.empty in @@ -381,25 +373,6 @@ module WP = ) in solver (); - - (* Printf.printf "Restarting globals\n"; - if tracing then trace "sol2" "Restarting globals\n"; - HM.iter (fun x _ -> - (* TODO: hack to identify globals *) - if Node.equal (S.Var.node x) (Function Cil.dummyFunDec) (* && (String.starts_with (Pretty.sprint ~width:max_int (S.Var.pretty_trace () x))"bwritten on") *) then ( - if tracing then trace "sol2" "Restarting global %a\n" S.Var.pretty_trace x; - HM.replace rho x (S.Dom.bot ()); - (* HM.remove rho x; *) - HM.remove wpoint x; (* otherwise gets immediately widened during resolve *) - HM.remove sides x; (* just in case *) - destabilize x; - destabilize_side x; - ) - ) rho; - - List.iter set_start st; (* TODO: necessary? *) - (* List.iter init vs; *) - solver (); *) (* Before we solved all unstable vars in rho with a rhs in a loop. This is unneeded overhead since it also solved unreachable vars (reachability only removes those from rho further down). *) (* After termination, only those variables are stable which are * - reachable from any of the queried variables vs, or From 628b607fc69b8558b4d1eadf2ad6c9e38b8274ba Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 29 Sep 2021 14:33:49 +0300 Subject: [PATCH 036/402] Move side_dep and side_infl clearing up in TD3 They can be removed right after incremental loading. They aren't used during solving. They will be repopulated for incremental saving. --- src/solvers/td3.ml | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/solvers/td3.ml b/src/solvers/td3.ml index 449baa68cc..5224670f51 100644 --- a/src/solvers/td3.ml +++ b/src/solvers/td3.ml @@ -353,6 +353,10 @@ module WP = print_data data "Data after clean-up" ); + (* reachability will populate these tables for incremental global restarting *) + HM.clear side_dep; + HM.clear side_infl; + List.iter set_start st; List.iter init vs; (* If we have multiple start variables vs, we might solve v1, then while solving v2 we side some global which v1 depends on with a new value. Then v1 is no longer stable and we have to solve it again. *) @@ -427,10 +431,7 @@ module WP = if tracing then trace "cache" "#caches: %d, max: %d, avg: %.2f\n" (List.length !cache_sizes) (List.max !cache_sizes) (avg !cache_sizes); ); - (* reachability will populate these tables for incremental global restarting *) - HM.clear side_dep; - HM.clear side_infl; - + (* reachability also populates side_dep and side_infl *) let reachability xs = let reachable = HM.create (HM.length rho) in let rec one_var x = From fd129fe3ef90d84887874a439c22403bd1b084a2 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 29 Sep 2021 14:37:40 +0300 Subject: [PATCH 037/402] Skip side effect restarting regression tests These require restarting globals during non-incremental solving. --- tests/regression/02-base/64-side-restart.c | 3 ++- tests/regression/02-base/65-side-restart-mutual.c | 3 ++- tests/regression/02-base/66-side-restart-self.c | 3 ++- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/tests/regression/02-base/64-side-restart.c b/tests/regression/02-base/64-side-restart.c index 1acf23b768..f14e7efb00 100644 --- a/tests/regression/02-base/64-side-restart.c +++ b/tests/regression/02-base/64-side-restart.c @@ -1,4 +1,5 @@ -// PARAM: --enable ana.int.interval +// SKIP PARAM: --enable ana.int.interval +// TODO: requires restart of global during/after normal solving #include #include diff --git a/tests/regression/02-base/65-side-restart-mutual.c b/tests/regression/02-base/65-side-restart-mutual.c index 4305eb534e..4e2226e17c 100644 --- a/tests/regression/02-base/65-side-restart-mutual.c +++ b/tests/regression/02-base/65-side-restart-mutual.c @@ -1,4 +1,5 @@ -// PARAM: --enable ana.int.interval +// SKIP PARAM: --enable ana.int.interval +// requires reuse of final local value for global restart #include #include diff --git a/tests/regression/02-base/66-side-restart-self.c b/tests/regression/02-base/66-side-restart-self.c index dbdea875d7..98d09d3f28 100644 --- a/tests/regression/02-base/66-side-restart-self.c +++ b/tests/regression/02-base/66-side-restart-self.c @@ -1,4 +1,5 @@ -// PARAM: --enable ana.int.interval +// SKIP PARAM: --enable ana.int.interval +// requires reuse of final local value for global restart #include #include From 96f5e3bbfe9ddd4bc0ad6c9c9a99963fe8d9345c Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 29 Sep 2021 15:50:36 +0300 Subject: [PATCH 038/402] Add restart_sided to TD3 --- src/solvers/td3.ml | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/solvers/td3.ml b/src/solvers/td3.ml index 5224670f51..475593efb8 100644 --- a/src/solvers/td3.ml +++ b/src/solvers/td3.ml @@ -77,8 +77,11 @@ module WP = let side_dep = data.side_dep in let side_infl = data.side_infl in + (* If true, incremental destabilized side-effected vars will be restarted. + If false, they are not. *) + let restart_sided = true in (* If true, incremental side-effected var restart will only restart destabilized globals (using hack). - if false, it will restart all destabilized side-effected vars. *) + If false, it will restart all destabilized side-effected vars. *) let restart_only_globals = false in let () = print_solver_stats := fun () -> @@ -291,6 +294,13 @@ module WP = ) w in + let destabilize_with_side = + if restart_sided then + destabilize_with_side + else + destabilize + in + (* If a global changes because of some assignment inside a function, we reanalyze, * but if it changes because of a different global initializer, then * if not exp.earlyglobs: the contexts of start functions will change, we don't find the value in rho and reanalyze; From 678f0d89810c69f95b4c5a6d2459249531a86799 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 29 Sep 2021 16:23:21 +0300 Subject: [PATCH 039/402] Add incremental test where local wpoint must be restarted after global restart --- tests/incremental/05-local-wpoint.c | 23 +++++++++++++++++++++++ tests/incremental/05-local-wpoint.json | 10 ++++++++++ tests/incremental/05-local-wpoint.patch | 10 ++++++++++ 3 files changed, 43 insertions(+) create mode 100644 tests/incremental/05-local-wpoint.c create mode 100644 tests/incremental/05-local-wpoint.json create mode 100644 tests/incremental/05-local-wpoint.patch diff --git a/tests/incremental/05-local-wpoint.c b/tests/incremental/05-local-wpoint.c new file mode 100644 index 0000000000..cdd9c48541 --- /dev/null +++ b/tests/incremental/05-local-wpoint.c @@ -0,0 +1,23 @@ +#include +#include + +int g = 1; + +void* t_fun(void *arg) { + g = 0; + return NULL; +} + +int main() { + pthread_t id; + pthread_create(&id, NULL, t_fun, NULL); // just go multithreaded + + int x; + x = g; + while (1) { + assert(x == 1); // unknown before, success after + x = g; + } + + return 0; +} \ No newline at end of file diff --git a/tests/incremental/05-local-wpoint.json b/tests/incremental/05-local-wpoint.json new file mode 100644 index 0000000000..ff773f6993 --- /dev/null +++ b/tests/incremental/05-local-wpoint.json @@ -0,0 +1,10 @@ +{ + "ana": { + "int": { + "interval": true + } + }, + "incremental": { + "wpoint": false + } +} \ No newline at end of file diff --git a/tests/incremental/05-local-wpoint.patch b/tests/incremental/05-local-wpoint.patch new file mode 100644 index 0000000000..2342e07535 --- /dev/null +++ b/tests/incremental/05-local-wpoint.patch @@ -0,0 +1,10 @@ +--- tests/incremental/05-local-wpoint.c 2021-09-29 16:30:17.199899879 +0300 ++++ "tests/incremental/05-local-wpoint copy.c" 2021-09-29 16:30:30.231977751 +0300 +@@ -4,7 +4,6 @@ + int g = 1; + + void* t_fun(void *arg) { +- g = 0; + return NULL; + } + From e028893b9b680ce0fc35a2f7102abc5b2a98f6be Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 29 Sep 2021 16:56:59 +0300 Subject: [PATCH 040/402] Add incremental test where local wpoint must be restarted after global restart due to read from old rho --- tests/incremental/06-local-wpoint-read.c | 24 ++++++++++++++++++++ tests/incremental/06-local-wpoint-read.json | 10 ++++++++ tests/incremental/06-local-wpoint-read.patch | 10 ++++++++ 3 files changed, 44 insertions(+) create mode 100644 tests/incremental/06-local-wpoint-read.c create mode 100644 tests/incremental/06-local-wpoint-read.json create mode 100644 tests/incremental/06-local-wpoint-read.patch diff --git a/tests/incremental/06-local-wpoint-read.c b/tests/incremental/06-local-wpoint-read.c new file mode 100644 index 0000000000..d6900bd3a5 --- /dev/null +++ b/tests/incremental/06-local-wpoint-read.c @@ -0,0 +1,24 @@ +#include +#include + +int g = 1; + +void* t_fun(void *arg) { + g = 0; + return NULL; +} + +int main() { + pthread_t id; + pthread_create(&id, NULL, t_fun, NULL); // just go multithreaded + + int x; + x = g; + while (1) { + g = x; + assert(x == 1); // unknown before, success after + x = g; + } + + return 0; +} \ No newline at end of file diff --git a/tests/incremental/06-local-wpoint-read.json b/tests/incremental/06-local-wpoint-read.json new file mode 100644 index 0000000000..ff773f6993 --- /dev/null +++ b/tests/incremental/06-local-wpoint-read.json @@ -0,0 +1,10 @@ +{ + "ana": { + "int": { + "interval": true + } + }, + "incremental": { + "wpoint": false + } +} \ No newline at end of file diff --git a/tests/incremental/06-local-wpoint-read.patch b/tests/incremental/06-local-wpoint-read.patch new file mode 100644 index 0000000000..1767552a45 --- /dev/null +++ b/tests/incremental/06-local-wpoint-read.patch @@ -0,0 +1,10 @@ +--- tests/incremental/06-local-wpoint-read.c 2021-09-29 16:55:20.461556453 +0300 ++++ "tests/incremental/06-local-wpoint-read copy.c" 2021-09-29 16:55:51.013749361 +0300 +@@ -4,7 +4,6 @@ + int g = 1; + + void* t_fun(void *arg) { +- g = 0; + return NULL; + } + From 5d64c6f8416ab2e48091616bdda1e08b12a97752 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 30 Sep 2021 10:36:11 +0300 Subject: [PATCH 041/402] Remove 80 character width from tracing output --- src/util/tracing.ml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/util/tracing.ml b/src/util/tracing.ml index d66be4fc48..90aa00db63 100644 --- a/src/util/tracing.ml +++ b/src/util/tracing.ml @@ -83,7 +83,7 @@ let traceTag (sys : string) : Pretty.doc = (text ((ind !indent_level) ^ "%%% " ^ sys ^ ": ")) let printtrace sys d: unit = - fprint stderr 80 ((traceTag sys) ++ d); + fprint stderr max_int ((traceTag sys) ++ d); flush stderr let gtrace always f sys var ?loc do_subsys fmt = From 9ee28513f7a07036f34764546f0f28e7f7a8d536 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 30 Sep 2021 10:40:07 +0300 Subject: [PATCH 042/402] Add variable splitting workaround for verify incompleteness --- src/framework/constraints.ml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/framework/constraints.ml b/src/framework/constraints.ml index 6c4c3755d0..301e814630 100644 --- a/src/framework/constraints.ml +++ b/src/framework/constraints.ml @@ -830,7 +830,10 @@ module GlobSolverFromEqSolver (Sol:GenericEqBoxSolver) | `L x -> begin match d with | `Lifted2 d -> LH.replace l' x d - | `Bot -> () + (* | `Bot -> () *) + (* Since Verify2 is broken and only checks existing keys, add it with local bottom value. + This works around some cases, where Verify2 would not detect a problem due to completely missing variable. *) + | `Bot -> LH.replace l' x (S.D.bot ()) | `Top -> failwith "GlobSolverFromEqSolver.split_vars: local variable has top value" | `Lifted1 _ -> failwith "GlobSolverFromEqSolver.split_vars: local variable has global value" end From 5a484bc110ba51a669c77de7fdf2edb801cb83d6 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 30 Sep 2021 10:44:26 +0300 Subject: [PATCH 043/402] Add local wpoint restarting to TD3 --- src/solvers/td3.ml | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/solvers/td3.ml b/src/solvers/td3.ml index 475593efb8..64d7a38d68 100644 --- a/src/solvers/td3.ml +++ b/src/solvers/td3.ml @@ -178,7 +178,15 @@ module WP = and eval l x y = if tracing then trace "sol2" "eval %a ## %a\n" S.Var.pretty_trace x S.Var.pretty_trace y; get_var_event y; - if HM.mem called y then HM.replace wpoint y (); + if HM.mem called y then ( + if not (HM.mem wpoint y) then ( + (* TODO: add boolean flag *) + if tracing then trace "sol2" "wpoint restart %a ## %a\n" S.Var.pretty_trace y S.Dom.pretty (HM.find_default rho y (S.Dom.bot ())); + HM.replace rho y (S.Dom.bot ()); + (* destabilize y *) (* TODO: would this do anything on called? *) + ); + HM.replace wpoint y (); + ); let tmp = simple_solve l x y in if HM.mem rho y then add_infl y x; tmp From 35d553c29158ab01287f1a9ec58fb55156f64877 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 30 Sep 2021 10:48:17 +0300 Subject: [PATCH 044/402] Fix unsound wpoint restart in TD3 by using non-outdated old value Since wpoint restart changes `HM.find rho x` during `eq`, the following non-equality check should use the new value, not the old outdated one. The TD3 paper does the comparison using the non-cached value anyway. --- src/solvers/td3.ml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/solvers/td3.ml b/src/solvers/td3.ml index 64d7a38d68..315e7b295c 100644 --- a/src/solvers/td3.ml +++ b/src/solvers/td3.ml @@ -124,13 +124,13 @@ module WP = HM.replace stable x (); HM.replace called x (); let wp = HM.mem wpoint x in - let old = HM.find rho x in let l = HM.create 10 in let tmp = eq x (eval l x) (side x) in (* let tmp = if GobConfig.get_bool "ana.opt.hashcons" then S.Dom.join (S.Dom.bot ()) tmp else tmp in (* Call hashcons via dummy join so that the tag of the rhs value is up to date. Otherwise we might get the same value as old, but still with a different tag (because no lattice operation was called after a change), and since Printable.HConsed.equal just looks at the tag, we would uneccessarily destabilize below. Seems like this does not happen. *) *) if tracing then trace "sol" "Var: %a\n" S.Var.pretty_trace x ; if tracing then trace "sol" "Contrib:%a\n" S.Dom.pretty tmp; HM.remove called x; + let old = HM.find rho x in let tmp = if not wp then tmp else From d29ef61ebb9064b8b78db0cf7ca1c9ab9f4ce2d9 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 30 Sep 2021 10:51:35 +0300 Subject: [PATCH 045/402] Add regression test for TD3 wpoint restart soundness --- .../00-sanity/28-wpoint-restart-sound.c | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 tests/regression/00-sanity/28-wpoint-restart-sound.c diff --git a/tests/regression/00-sanity/28-wpoint-restart-sound.c b/tests/regression/00-sanity/28-wpoint-restart-sound.c new file mode 100644 index 0000000000..511d0b5d25 --- /dev/null +++ b/tests/regression/00-sanity/28-wpoint-restart-sound.c @@ -0,0 +1,24 @@ +// PARAM: --enable ana.int.interval +#include +#include + +int g = 0; + +void *worker(void *arg ) +{ + return NULL; +} + +int main(int argc , char **argv ) +{ + pthread_t tid; + pthread_create(& tid, NULL, & worker, NULL); + + while (g >= 10) { + + } + assert(1); // reachable + g++; + assert(1); // reachable + return 0; +} From 617452f532c8a1873ff0faf247e75dd017374ca8 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 30 Sep 2021 10:54:36 +0300 Subject: [PATCH 046/402] Add restart_wpoint to TD3 --- src/solvers/td3.ml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/solvers/td3.ml b/src/solvers/td3.ml index 315e7b295c..e6933c229d 100644 --- a/src/solvers/td3.ml +++ b/src/solvers/td3.ml @@ -83,6 +83,9 @@ module WP = (* If true, incremental side-effected var restart will only restart destabilized globals (using hack). If false, it will restart all destabilized side-effected vars. *) let restart_only_globals = false in + (* If true, wpoint will be restarted to bot when added. + This allows incremental to avoid reusing and republishing imprecise local values due to globals (which get restarted). *) + let restart_wpoint = true in let () = print_solver_stats := fun () -> Printf.printf "|rho|=%d\n|called|=%d\n|stable|=%d\n|infl|=%d\n|wpoint|=%d\n|side_dep|=%d\n|side_infl|=%d\n" @@ -179,8 +182,7 @@ module WP = if tracing then trace "sol2" "eval %a ## %a\n" S.Var.pretty_trace x S.Var.pretty_trace y; get_var_event y; if HM.mem called y then ( - if not (HM.mem wpoint y) then ( - (* TODO: add boolean flag *) + if restart_wpoint && not (HM.mem wpoint y) then ( if tracing then trace "sol2" "wpoint restart %a ## %a\n" S.Var.pretty_trace y S.Dom.pretty (HM.find_default rho y (S.Dom.bot ())); HM.replace rho y (S.Dom.bot ()); (* destabilize y *) (* TODO: would this do anything on called? *) From 36889e8c842947ef4af5f970b52e4e1da9db026a Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 30 Sep 2021 11:03:34 +0300 Subject: [PATCH 047/402] Comment local wpoint restarting in TD3 --- src/solvers/td3.ml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/solvers/td3.ml b/src/solvers/td3.ml index e6933c229d..4cdd1e0926 100644 --- a/src/solvers/td3.ml +++ b/src/solvers/td3.ml @@ -126,6 +126,11 @@ module WP = if not (HM.mem called x || HM.mem stable x) then ( HM.replace stable x (); HM.replace called x (); + (* Here we cache HM.mem wpoint x before eq. If during eq eval makes x wpoint, then be still don't apply widening the first time, but just overwrite. + It means that the first iteration at wpoint is still precise. + This doesn't matter during normal solving (?), because old would be bot. + This matters during incremental loading, when wpoints have been removed (or not marshaled) and are redetected. + Then the previous local wpoint value is discarded automagically and not joined/widened, providing limited restarting of local wpoints. (See eval for more complete restarting.) *) let wp = HM.mem wpoint x in let l = HM.create 10 in let tmp = eq x (eval l x) (side x) in @@ -183,6 +188,9 @@ module WP = get_var_event y; if HM.mem called y then ( if restart_wpoint && not (HM.mem wpoint y) then ( + (* Even though solve cleverly restarts redetected wpoints during incremental load, the loop body would be calculated based on the old wpoint value. + The loop body might then side effect the old value, see tests/incremental/06-local-wpoint-read. + Here we avoid this, by setting it to bottom for the loop body eval. *) if tracing then trace "sol2" "wpoint restart %a ## %a\n" S.Var.pretty_trace y S.Dom.pretty (HM.find_default rho y (S.Dom.bot ())); HM.replace rho y (S.Dom.bot ()); (* destabilize y *) (* TODO: would this do anything on called? *) From 60cdb2946b0c5eb86bb29e70f00df949dc7bb24d Mon Sep 17 00:00:00 2001 From: Vesal Vojdani Date: Mon, 4 Oct 2021 15:17:16 +0300 Subject: [PATCH 048/402] [skip ci] Add paper example; success, it works, all good to go ;) --- tests/incremental/05-paper-example.c | 42 ++++++++++++++++++++++++ tests/incremental/05-paper-example.json | 7 ++++ tests/incremental/05-paper-example.patch | 4 +++ 3 files changed, 53 insertions(+) create mode 100644 tests/incremental/05-paper-example.c create mode 100644 tests/incremental/05-paper-example.json create mode 100644 tests/incremental/05-paper-example.patch diff --git a/tests/incremental/05-paper-example.c b/tests/incremental/05-paper-example.c new file mode 100644 index 0000000000..735728db07 --- /dev/null +++ b/tests/incremental/05-paper-example.c @@ -0,0 +1,42 @@ +#include +#include + +pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; + +int (*fp)() = NULL; + +int bad() { + return -1; +} + +int good() { + return 1; +} + +void* consumer(void *arg) { + int res = 0; + pthread_mutex_lock(&mutex); + if (fp != NULL) { + res = fp(); + } + pthread_mutex_unlock(&mutex); + assert(res >= 0); + res = 0; + // change absorbed + return NULL; +} + +void* producer(void *arg) { + int res = 0; + pthread_mutex_lock(&mutex); + fp = bad; + pthread_mutex_unlock(&mutex); + return NULL; +} + +int main() { + pthread_t id1 = NULL, id2 = NULL; + pthread_create(&id1, NULL, consumer, NULL); + pthread_create(&id2, NULL, producer, NULL); + return 0; +} \ No newline at end of file diff --git a/tests/incremental/05-paper-example.json b/tests/incremental/05-paper-example.json new file mode 100644 index 0000000000..5be265f269 --- /dev/null +++ b/tests/incremental/05-paper-example.json @@ -0,0 +1,7 @@ +{ + "ana": { + "int": { + "interval": true + } + } +} \ No newline at end of file diff --git a/tests/incremental/05-paper-example.patch b/tests/incremental/05-paper-example.patch new file mode 100644 index 0000000000..21c08b5911 --- /dev/null +++ b/tests/incremental/05-paper-example.patch @@ -0,0 +1,4 @@ +32c32 +< fp = bad; +--- +> fp = good; From 21fa6a65b36cd4ce5c2fd5b68db8092711fd7173 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Tue, 5 Oct 2021 11:03:32 +0300 Subject: [PATCH 049/402] Add incremental test where function call is removed This currently still works with restart_only_globals=true, because destabilize_with_side follows all side effects nevertheless. --- src/solvers/td3.ml | 1 + tests/incremental/06-call-remove.c | 25 +++++++++++++++++++++++++ tests/incremental/06-call-remove.json | 3 +++ tests/incremental/06-call-remove.patch | 11 +++++++++++ 4 files changed, 40 insertions(+) create mode 100644 tests/incremental/06-call-remove.c create mode 100644 tests/incremental/06-call-remove.json create mode 100644 tests/incremental/06-call-remove.patch diff --git a/src/solvers/td3.ml b/src/solvers/td3.ml index 9b47d76af6..90ee9e6e0b 100644 --- a/src/solvers/td3.ml +++ b/src/solvers/td3.ml @@ -287,6 +287,7 @@ module WP = (* destabilize side infl *) let w = HM.find_default side_infl x VS.empty in HM.remove side_infl x; + (* TODO: should this also be conditional on restart_only_globals? right now goes through function entry side effects, but just doesn't restart them *) VS.iter (fun y -> if tracing then trace "sol2" "destabilize_with_side %a side_infl %a\n" S.Var.pretty_trace x S.Var.pretty_trace y; HM.remove stable y; diff --git a/tests/incremental/06-call-remove.c b/tests/incremental/06-call-remove.c new file mode 100644 index 0000000000..87aec95350 --- /dev/null +++ b/tests/incremental/06-call-remove.c @@ -0,0 +1,25 @@ +#include +#include + +int g = 1; + +void foo() { + g = 2; +} + +void* t_fun(void *arg) { + foo(); + return NULL; +} + +void* t_fun2(void *arg) { + assert(g == 1); // unknown before, success after + return NULL; +} + +int main() { + pthread_t id, id2; + pthread_create(&id2, NULL, t_fun2, NULL); + pthread_create(&id, NULL, t_fun, NULL); + return 0; +} \ No newline at end of file diff --git a/tests/incremental/06-call-remove.json b/tests/incremental/06-call-remove.json new file mode 100644 index 0000000000..0e0dcd235c --- /dev/null +++ b/tests/incremental/06-call-remove.json @@ -0,0 +1,3 @@ +{ + +} \ No newline at end of file diff --git a/tests/incremental/06-call-remove.patch b/tests/incremental/06-call-remove.patch new file mode 100644 index 0000000000..8c96c9d0c6 --- /dev/null +++ b/tests/incremental/06-call-remove.patch @@ -0,0 +1,11 @@ +--- tests/incremental/06-call-remove.c 2021-10-05 10:49:27.305643809 +0300 ++++ "tests/incremental/06-call-remove copy.c" 2021-10-05 10:49:37.397808651 +0300 +@@ -8,7 +8,7 @@ + } + + void* t_fun(void *arg) { +- foo(); ++ // foo(); + return NULL; + } + From 87103f5e8bc8900e5171bcb34bd0af1ebde99bd7 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Tue, 5 Oct 2021 11:21:39 +0300 Subject: [PATCH 050/402] Inline non-incremental postsolver in TD3 --- src/solvers/td3.ml | 55 +++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 52 insertions(+), 3 deletions(-) diff --git a/src/solvers/td3.ml b/src/solvers/td3.ml index 5bed77340a..10ac1d00ad 100644 --- a/src/solvers/td3.ml +++ b/src/solvers/td3.ml @@ -21,8 +21,6 @@ module WP = functor (S:EqConstrSys) -> functor (HM:Hashtbl.S with type key = S.v) -> struct - module Post = PostSolver.MakeList (PostSolver.ListArgFromStdArg (S) (HM) (Arg)) - include Generic.SolverStats (S) (HM) module VS = Set.Make (S.Var) @@ -388,7 +386,58 @@ module WP = print_newline (); ); - Post.post st vs rho; (* TODO: add side_infl postsolver *) + let module Post = PostSolver.MakeList (PostSolver.ListArgFromStdArg (S) (HM) (Arg)) in + begin match Post.postsolver_opt with + | None -> () + | Some (module PS) -> + let open GobConfig in + + let post xs vs vh = + if get_bool "dbg.verbose" then + print_endline "Postsolving\n"; + + let module StartS = + struct + include S + let starts = xs + end + in + let module S = PostSolver.EqConstrSysFromStartEqConstrSys (StartS) in + + Goblintutil.postsolving := true; + PS.init (); + + let reachable = HM.create (HM.length vh) in + let rec one_var x = + if not (HM.mem reachable x) then ( + HM.replace reachable x (); + Option.may (one_constraint x) (S.system x) + ) + and one_constraint x f = + let get y = + one_var y; + try HM.find vh y with Not_found -> S.Dom.bot () + in + let set y d = + PS.one_side ~vh ~x ~y ~d; + (* check before recursing *) + one_var y + in + let rhs = f get set in + PS.one_constraint ~vh ~x ~rhs + in + List.iter one_var vs; + + PS.finalize ~vh ~reachable; + Goblintutil.postsolving := false + in + + let post xs vs vh = + Stats.time "postsolver" (post xs vs) vh + in + + post st vs rho (* TODO: add side_infl postsolver *) + end; {st; infl; sides; rho; wpoint; stable} From 38dc266ed3ed0aa76bcf05b2d4d6fcda41f3287a Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Tue, 5 Oct 2021 11:27:08 +0300 Subject: [PATCH 051/402] Add superstable set to TD3 to optimize incremental postsolving (issue #368) --- src/solvers/td3.ml | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/solvers/td3.ml b/src/solvers/td3.ml index 10ac1d00ad..a80d58fba0 100644 --- a/src/solvers/td3.ml +++ b/src/solvers/td3.ml @@ -78,6 +78,10 @@ module WP = let wpoint = data.wpoint in let stable = data.stable in + (* In incremental load, initially stable nodes, which are never destabilized. + These don't have to be re-verified and warnings can be reused. *) + let superstable = HM.copy stable in + let () = print_solver_stats := fun () -> Printf.printf "|rho|=%d\n|called|=%d\n|stable|=%d\n|infl|=%d\n|wpoint|=%d\n" (HM.length rho) (HM.length called) (HM.length stable) (HM.length infl) (HM.length wpoint); @@ -99,6 +103,7 @@ module WP = HM.replace infl x VS.empty; VS.iter (fun y -> HM.remove stable y; + HM.remove superstable y; if not (HM.mem called y) then destabilize y ) w and destabilize_vs x = (* TODO remove? Only used for side_widen cycle. *) @@ -108,6 +113,7 @@ module WP = VS.fold (fun y b -> let was_stable = HM.mem stable y in HM.remove stable y; + HM.remove superstable y; HM.mem called y || destabilize_vs y || b || was_stable && List.mem y vs ) w false and solve x phase = @@ -145,6 +151,7 @@ module WP = (solve[@tailcall]) x Widen; ) else if term && phase = Widen then ( HM.remove stable x; + HM.remove superstable x; (solve[@tailcall]) x Narrow; ) else if not space && (not term || phase = Narrow) then (* this makes e.g. nested loops precise, ex. tests/regression/34-localization/01-nested.c - if we do not remove wpoint, the inner loop head will stay a wpoint and widen the outer loop variable. *) HM.remove wpoint x; @@ -407,7 +414,7 @@ module WP = Goblintutil.postsolving := true; PS.init (); - let reachable = HM.create (HM.length vh) in + let reachable = HM.copy superstable in (* consider superstable reached: stop recursion (evaluation) and keep from being pruned *) let rec one_var x = if not (HM.mem reachable x) then ( HM.replace reachable x (); From 6412ace64a6edf030ed788e253a734c0b5cca2c1 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Tue, 5 Oct 2021 13:40:35 +0300 Subject: [PATCH 052/402] Add superstable messages reuse to TD3 (issue #368) --- src/solvers/td3.ml | 46 +++++++++++++++++++++++++++++++++++++++++--- src/util/messages.ml | 5 ++++- 2 files changed, 47 insertions(+), 4 deletions(-) diff --git a/src/solvers/td3.ml b/src/solvers/td3.ml index a80d58fba0..51a7f25155 100644 --- a/src/solvers/td3.ml +++ b/src/solvers/td3.ml @@ -30,7 +30,8 @@ module WP = mutable sides: VS.t HM.t; mutable rho: S.Dom.t HM.t; mutable wpoint: unit HM.t; - mutable stable: unit HM.t + mutable stable: unit HM.t; + mutable var_messages: Message.t HM.t; } type marshal = solver_data @@ -41,7 +42,8 @@ module WP = sides = HM.create 10; rho = HM.create 10; wpoint = HM.create 10; - stable = HM.create 10 + stable = HM.create 10; + var_messages = HM.create 10; } let clear_data data = @@ -65,6 +67,28 @@ module WP = type phase = Widen | Narrow + module S = + struct + include S + + let current_var = ref None + + let system x = + match S.system x with + | None -> None + | Some f -> + let f' get set = + let old_current_var = !current_var in + current_var := Some x; + Fun.protect ~finally:(fun () -> + current_var := old_current_var + ) (fun () -> + f get set + ) + in + Some f' + end + let solve box st vs data = let term = GobConfig.get_bool "exp.solver.td3.term" in let side_widen = GobConfig.get_string "exp.solver.td3.side_widen" in @@ -82,6 +106,8 @@ module WP = These don't have to be re-verified and warnings can be reused. *) let superstable = HM.copy stable in + let var_messages = data.var_messages in + let () = print_solver_stats := fun () -> Printf.printf "|rho|=%d\n|called|=%d\n|stable|=%d\n|infl|=%d\n|wpoint|=%d\n" (HM.length rho) (HM.length called) (HM.length stable) (HM.length infl) (HM.length wpoint); @@ -393,6 +419,8 @@ module WP = print_newline (); ); + HM.filteri_inplace (fun x _ -> HM.mem superstable x) var_messages; + let module Post = PostSolver.MakeList (PostSolver.ListArgFromStdArg (S) (HM) (Arg)) in begin match Post.postsolver_opt with | None -> () @@ -403,6 +431,7 @@ module WP = if get_bool "dbg.verbose" then print_endline "Postsolving\n"; + let module OutS = S in let module StartS = struct include S @@ -414,6 +443,16 @@ module WP = Goblintutil.postsolving := true; PS.init (); + HM.iter (fun _ m -> + Messages.add m + ) var_messages; + + Messages.Table.add_hook := (fun m -> + match !OutS.current_var with + | Some x -> HM.add var_messages x m + | None -> () + ); + let reachable = HM.copy superstable in (* consider superstable reached: stop recursion (evaluation) and keep from being pruned *) let rec one_var x = if not (HM.mem reachable x) then ( @@ -446,7 +485,7 @@ module WP = post st vs rho (* TODO: add side_infl postsolver *) end; - {st; infl; sides; rho; wpoint; stable} + {st; infl; sides; rho; wpoint; stable; var_messages} let solve box st vs = let reuse_stable = GobConfig.get_bool "incremental.stable" in @@ -496,6 +535,7 @@ module WP = ) data.infl; data.infl <- infl'; data.st <- List.map (fun (k, v) -> S.Var.relift k, S.Dom.join (S.Dom.bot ()) v) data.st; + (* TODO: relift var_messages? *) ); if not reuse_stable then ( print_endline "Destabilizing everything!"; diff --git a/src/util/messages.ml b/src/util/messages.ml index e2f11cb310..05533ca8ac 100644 --- a/src/util/messages.ml +++ b/src/util/messages.ml @@ -125,9 +125,12 @@ struct let mem = MH.mem messages_table + let add_hook: (Message.t -> unit) ref = ref (fun _ -> ()) + let add m = MH.replace messages_table m (); - messages_list := m :: !messages_list + messages_list := m :: !messages_list; + !add_hook m let to_yojson () = [%to_yojson: Message.t list] (List.rev !messages_list) (* reverse to get in addition order *) From 2e0790de124796999c0c77087db25dcb1dc70bd9 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 6 Oct 2021 10:13:30 +0300 Subject: [PATCH 053/402] Document side_dep and side_infl in TD3 --- src/solvers/td3.ml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/solvers/td3.ml b/src/solvers/td3.ml index 90ee9e6e0b..faf1a33330 100644 --- a/src/solvers/td3.ml +++ b/src/solvers/td3.ml @@ -30,8 +30,8 @@ module WP = mutable rho: S.Dom.t HM.t; mutable wpoint: unit HM.t; mutable stable: unit HM.t; - mutable side_dep: VS.t HM.t; - mutable side_infl: VS.t HM.t; + mutable side_dep: VS.t HM.t; (** Dependencies of side-effected variables. Knowing these allows restarting them and re-triggering all side effects. *) + mutable side_infl: VS.t HM.t; (** Influences to side-effected variables. Not normally in [infl], but used for restarting them. *) } let create_empty_data () = { From fe0ab6e523d60d10d97c98980fb1758fa2dc15c3 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 6 Oct 2021 10:16:47 +0300 Subject: [PATCH 054/402] Add options for side-effected variable restarting in incremental --- src/solvers/td3.ml | 4 ++-- src/util/defaults.ml | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/solvers/td3.ml b/src/solvers/td3.ml index faf1a33330..c0c4e3e42b 100644 --- a/src/solvers/td3.ml +++ b/src/solvers/td3.ml @@ -79,10 +79,10 @@ module WP = let side_infl = data.side_infl in (* If true, incremental destabilized side-effected vars will be restarted. If false, they are not. *) - let restart_sided = true in + let restart_sided = GobConfig.get_bool "incremental.restart.sided.enabled" in (* If true, incremental side-effected var restart will only restart destabilized globals (using hack). If false, it will restart all destabilized side-effected vars. *) - let restart_only_globals = false in + let restart_only_globals = GobConfig.get_bool "incremental.restart.sided.only-global" in let () = print_solver_stats := fun () -> Printf.printf "|rho|=%d\n|called|=%d\n|stable|=%d\n|infl|=%d\n|wpoint|=%d\n|side_dep|=%d\n|side_infl|=%d\n" diff --git a/src/util/defaults.ml b/src/util/defaults.ml index a59d937958..272a83aa7f 100644 --- a/src/util/defaults.ml +++ b/src/util/defaults.ml @@ -152,6 +152,8 @@ let _ = () ; reg Incremental "incremental.save" "false" "Store incremental analysis results." ; reg Incremental "incremental.stable" "true" "Reuse the stable set and selectively destabilize it (recommended)." ; reg Incremental "incremental.wpoint" "false" "Reuse the wpoint set (not recommended). Reusing the wpoint will combine existing results at previous widening points." + ; reg Incremental "incremental.restart.sided.enabled" "true" "TODO" + ; reg Incremental "incremental.restart.sided.only-global" "false" "TODO" (* {4 category [Semantics]} *) let _ = () From a6912084d19b583e2e5b60cf3642b59f29e4f249 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 6 Oct 2021 11:13:27 +0300 Subject: [PATCH 055/402] Add option to restart wpoint only once in TD3 --- src/solvers/td3.ml | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/solvers/td3.ml b/src/solvers/td3.ml index 636d6fb20b..26e0fc4fc0 100644 --- a/src/solvers/td3.ml +++ b/src/solvers/td3.ml @@ -86,6 +86,10 @@ module WP = (* If true, wpoint will be restarted to bot when added. This allows incremental to avoid reusing and republishing imprecise local values due to globals (which get restarted). *) let restart_wpoint = true in + (* If true, each wpoint will be restarted once when added. + If false, it will be restarted each time it is added again (wpoints are removed after Narrow). *) + let restart_once = true in + let restarted_wpoint = HM.create 10 in let () = print_solver_stats := fun () -> Printf.printf "|rho|=%d\n|called|=%d\n|stable|=%d\n|infl|=%d\n|wpoint|=%d\n|side_dep|=%d\n|side_infl|=%d\n" @@ -191,9 +195,13 @@ module WP = (* Even though solve cleverly restarts redetected wpoints during incremental load, the loop body would be calculated based on the old wpoint value. The loop body might then side effect the old value, see tests/incremental/06-local-wpoint-read. Here we avoid this, by setting it to bottom for the loop body eval. *) - if tracing then trace "sol2" "wpoint restart %a ## %a\n" S.Var.pretty_trace y S.Dom.pretty (HM.find_default rho y (S.Dom.bot ())); - HM.replace rho y (S.Dom.bot ()); - (* destabilize y *) (* TODO: would this do anything on called? *) + if not (restart_once && HM.mem restarted_wpoint y) then ( + if tracing then trace "sol2" "wpoint restart %a ## %a\n" S.Var.pretty_trace y S.Dom.pretty (HM.find_default rho y (S.Dom.bot ())); + HM.replace rho y (S.Dom.bot ()); + (* destabilize y *) (* TODO: would this do anything on called? *) + if restart_once then (* avoid populating hashtable unnecessarily *) + HM.replace restarted_wpoint y (); + ) ); HM.replace wpoint y (); ); From e45b904e154406809b76854446dda92d12bb4a42 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 6 Oct 2021 11:14:38 +0300 Subject: [PATCH 056/402] Add options for wpoint restarting in incremental --- src/solvers/td3.ml | 4 ++-- src/util/defaults.ml | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/solvers/td3.ml b/src/solvers/td3.ml index 26e0fc4fc0..6609dbcb35 100644 --- a/src/solvers/td3.ml +++ b/src/solvers/td3.ml @@ -85,10 +85,10 @@ module WP = let restart_only_globals = GobConfig.get_bool "incremental.restart.sided.only-global" in (* If true, wpoint will be restarted to bot when added. This allows incremental to avoid reusing and republishing imprecise local values due to globals (which get restarted). *) - let restart_wpoint = true in + let restart_wpoint = GobConfig.get_bool "incremental.restart.wpoint.enabled" in (* If true, each wpoint will be restarted once when added. If false, it will be restarted each time it is added again (wpoints are removed after Narrow). *) - let restart_once = true in + let restart_once = GobConfig.get_bool "incremental.restart.wpoint.once" in let restarted_wpoint = HM.create 10 in let () = print_solver_stats := fun () -> diff --git a/src/util/defaults.ml b/src/util/defaults.ml index 272a83aa7f..4e84715dd0 100644 --- a/src/util/defaults.ml +++ b/src/util/defaults.ml @@ -154,6 +154,8 @@ let _ = () ; reg Incremental "incremental.wpoint" "false" "Reuse the wpoint set (not recommended). Reusing the wpoint will combine existing results at previous widening points." ; reg Incremental "incremental.restart.sided.enabled" "true" "TODO" ; reg Incremental "incremental.restart.sided.only-global" "false" "TODO" + ; reg Incremental "incremental.restart.wpoint.enabled" "true" "TODO" + ; reg Incremental "incremental.restart.wpoint.once" "true" "TODO" (* {4 category [Semantics]} *) let _ = () From 437a07f6100a31c8347e06b0bc6256a7f4606478 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 6 Oct 2021 11:22:03 +0300 Subject: [PATCH 057/402] Add comment about finding old value after eq in TD3 --- src/solvers/td3.ml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/solvers/td3.ml b/src/solvers/td3.ml index 6609dbcb35..a635c71b16 100644 --- a/src/solvers/td3.ml +++ b/src/solvers/td3.ml @@ -142,7 +142,7 @@ module WP = if tracing then trace "sol" "Var: %a\n" S.Var.pretty_trace x ; if tracing then trace "sol" "Contrib:%a\n" S.Dom.pretty tmp; HM.remove called x; - let old = HM.find rho x in + let old = HM.find rho x in (* find old value after eq since wpoint restarting in eq/eval might have changed it meanwhile *) let tmp = if not wp then tmp else From 7abb940384e7d5f7a30188d5b227cb6b1727800d Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 6 Oct 2021 17:43:33 +0300 Subject: [PATCH 058/402] Add regression test where TD3 aborting with self-dependency and fixed switch to Narrow is unsound --- tests/regression/04-mutex/59-td3-self-abort.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 tests/regression/04-mutex/59-td3-self-abort.c diff --git a/tests/regression/04-mutex/59-td3-self-abort.c b/tests/regression/04-mutex/59-td3-self-abort.c new file mode 100644 index 0000000000..50a2ece39d --- /dev/null +++ b/tests/regression/04-mutex/59-td3-self-abort.c @@ -0,0 +1,15 @@ +#include + +int myglobal; + +void *t_fun(void *arg) { + myglobal=1; // RACE! + return NULL; +} + +int main(void) { + pthread_t id; + pthread_create(&id, NULL, t_fun, NULL); + myglobal = myglobal+1; // RACE! + return 0; +} From 365e752ec513ccef1df7f95c946bc83ceee49497 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 6 Oct 2021 16:09:12 +0300 Subject: [PATCH 059/402] Add more TD3 tracing --- src/solvers/td3.ml | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/solvers/td3.ml b/src/solvers/td3.ml index 94823e5f68..2ec4c05d19 100644 --- a/src/solvers/td3.ml +++ b/src/solvers/td3.ml @@ -126,7 +126,7 @@ module WP = HM.mem called y || destabilize_vs y || b || was_stable && List.mem y vs ) w false and solve ?(abort=true) x phase (changed: bool): bool = - if tracing then trace "sol2" "solve %a, called: %b, stable: %b\n" S.Var.pretty_trace x (HM.mem called x) (HM.mem stable x); + if tracing then trace "sol2" "solve %a, phase: %s, changed: %b, abort: %b, called: %b, stable: %b\n" S.Var.pretty_trace x (match phase with Widen -> "Widen" | Narrow -> "Narrow") changed abort (HM.mem called x) (HM.mem stable x); init x; assert (S.system x <> None); if not (HM.mem called x || HM.mem stable x) then ( @@ -136,15 +136,22 @@ module WP = let old = HM.find rho x in let l = HM.create 10 in let eval' = + if tracing then trace "sol2" "eval' %a abort=%b destab_dep=%b\n" S.Var.pretty_trace x abort (HM.mem destab_dep x); if HM.mem destab_dep x && abort then ( + let vs_pretty () vs = + VS.fold (fun x acc -> Pretty.dprintf "%a, %a" S.Var.pretty_trace x Pretty.insert acc) vs Pretty.nil + in let unasked_dep_x = ref (HM.find destab_dep x) in + if tracing then trace "sol2" "eval' %a dep=%a\n" S.Var.pretty_trace x vs_pretty !unasked_dep_x; let all_dep_x_unchanged = ref true in fun y -> let (d, changed) = eval l x y in + if tracing then trace "sol2" "eval' %a asked %a changed=%b mem=%b\n" S.Var.pretty_trace x S.Var.pretty_trace y changed (VS.mem y !unasked_dep_x); if VS.mem y !unasked_dep_x then ( unasked_dep_x := VS.remove y !unasked_dep_x; if changed then all_dep_x_unchanged := false; + if tracing then trace "sol2" "eval' %a asked %a checking abort unasked=%a all_unchanged=%b front=%b\n" S.Var.pretty_trace x S.Var.pretty_trace y vs_pretty !unasked_dep_x !all_dep_x_unchanged (HM.mem destab_front x); if VS.is_empty !unasked_dep_x && !all_dep_x_unchanged && not (HM.mem destab_front x) then (* must check front here, because each eval might change it for x *) raise AbortEq ); @@ -182,6 +189,7 @@ module WP = if tracing then trace "cache" "cache size %d for %a\n" (HM.length l) S.Var.pretty_trace x; cache_sizes := HM.length l :: !cache_sizes; if not (Stats.time "S.Dom.equal" (fun () -> S.Dom.equal old tmp) ()) then ( + if tracing then trace "sol" "Changed\n"; update_var_event x old tmp; HM.replace rho x tmp; HM.replace called_changed x (); @@ -212,7 +220,7 @@ module WP = HM.remove stable x; (solve[@tailcall]) ~abort:false x Narrow changed ) else if not space && (not term || phase = Narrow) then ( (* this makes e.g. nested loops precise, ex. tests/regression/34-localization/01-nested.c - if we do not remove wpoint, the inner loop head will stay a wpoint and widen the outer loop variable. *) - if tracing then trace "sol2" "solve removing wpoint %a\n" S.Var.pretty_trace x; + if tracing then trace "sol2" "solve removing wpoint %a (%b)\n" S.Var.pretty_trace x (HM.mem wpoint x); HM.remove wpoint x; changed ) From e46f85b67ad0c53fae1861a0f68b1515db32097c Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 6 Oct 2021 17:54:37 +0300 Subject: [PATCH 060/402] Fix TD3 self side destabilization removing from front --- src/solvers/td3.ml | 59 ++++++++++++++++++++++++++-------------------- 1 file changed, 34 insertions(+), 25 deletions(-) diff --git a/src/solvers/td3.ml b/src/solvers/td3.ml index 2ec4c05d19..a7e29fbf3b 100644 --- a/src/solvers/td3.ml +++ b/src/solvers/td3.ml @@ -193,39 +193,48 @@ module WP = update_var_event x old tmp; HM.replace rho x tmp; HM.replace called_changed x (); - if HM.mem destab_front x then ( - HM.remove destab_front x; - if HM.mem destab_infl x then ( - VS.iter (fun y -> - if tracing then trace "sol2" "pushing front from %a to %a\n" S.Var.pretty_trace x S.Var.pretty_trace y; - HM.replace destab_front y () - ) (HM.find destab_infl x) - ); - HM.remove destab_infl x + if HM.mem stable x then ( + (* If some side during eq made x unstable, then it should remain in destab_front. + Otherwise recursive solve might prematurely abort it. *) + if HM.mem destab_front x then ( + HM.remove destab_front x; + if HM.mem destab_infl x then ( + VS.iter (fun y -> + if tracing then trace "sol2" "pushing front from %a to %a\n" S.Var.pretty_trace x S.Var.pretty_trace y; + HM.replace destab_front y () + ) (HM.find destab_infl x) + ); + HM.remove destab_infl x + ) ); destabilize x; (solve[@tailcall]) x phase true ) else ( - if HM.mem destab_front x then ( - HM.remove destab_front x; - if tracing then trace "sol2" "not pushing front from %a\n" S.Var.pretty_trace x; - (* don't push front here *) - HM.remove destab_infl x - ); + (* TODO: why non-equal and non-stable checks in switched order compared to TD3 paper? *) if not (HM.mem stable x) then ( + (* If some side during eq made x unstable, then it should remain in destab_front. + Otherwise recursive solve might prematurely abort it. *) if tracing then trace "sol2" "solve still unstable %a\n" S.Var.pretty_trace x; (solve[@tailcall]) x Widen changed - ) else if term && phase = Widen && HM.mem wpoint x then ( (* TODO: or use wp? *) - if tracing then trace "sol2" "solve switching to narrow %a\n" S.Var.pretty_trace x; - HM.remove stable x; - (solve[@tailcall]) ~abort:false x Narrow changed - ) else if not space && (not term || phase = Narrow) then ( (* this makes e.g. nested loops precise, ex. tests/regression/34-localization/01-nested.c - if we do not remove wpoint, the inner loop head will stay a wpoint and widen the outer loop variable. *) - if tracing then trace "sol2" "solve removing wpoint %a (%b)\n" S.Var.pretty_trace x (HM.mem wpoint x); - HM.remove wpoint x; - changed + ) else ( + if HM.mem destab_front x then ( + HM.remove destab_front x; + if tracing then trace "sol2" "not pushing front from %a\n" S.Var.pretty_trace x; + (* don't push front here *) + HM.remove destab_infl x + ); + if term && phase = Widen && HM.mem wpoint x then ( (* TODO: or use wp? *) + if tracing then trace "sol2" "solve switching to narrow %a\n" S.Var.pretty_trace x; + HM.remove stable x; + (solve[@tailcall]) ~abort:false x Narrow changed + ) else if not space && (not term || phase = Narrow) then ( (* this makes e.g. nested loops precise, ex. tests/regression/34-localization/01-nested.c - if we do not remove wpoint, the inner loop head will stay a wpoint and widen the outer loop variable. *) + if tracing then trace "sol2" "solve removing wpoint %a (%b)\n" S.Var.pretty_trace x (HM.mem wpoint x); + HM.remove wpoint x; + changed + ) + else + changed ) - else - changed ) ) else if HM.mem called x then From 53359adda7580cb506970956b48062741da051cd Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 7 Oct 2021 12:34:38 +0300 Subject: [PATCH 061/402] Add TD3 test where complex self-abort causes verify error --- .../36-apron/71-td3-self-abort-complex.c | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 tests/regression/36-apron/71-td3-self-abort-complex.c diff --git a/tests/regression/36-apron/71-td3-self-abort-complex.c b/tests/regression/36-apron/71-td3-self-abort-complex.c new file mode 100644 index 0000000000..d53beb6012 --- /dev/null +++ b/tests/regression/36-apron/71-td3-self-abort-complex.c @@ -0,0 +1,30 @@ +// SKIP PARAM: --set ana.activated[+] apron +#include +#include + +int g = 1; +int h = 1; +pthread_mutex_t A = PTHREAD_MUTEX_INITIALIZER; + +void *t_fun(void *arg) { + int x, y; // rand + pthread_mutex_lock(&A); + g = x; + h = x; + pthread_mutex_unlock(&A); + pthread_mutex_lock(&A); + pthread_mutex_unlock(&A); + pthread_mutex_lock(&A); + if (y) + g = x; + assert(g == h); // UNKNOWN? + pthread_mutex_unlock(&A); + return NULL; +} + +int main(void) { + pthread_t id; + pthread_create(&id, NULL, t_fun, NULL); + + return 0; +} From 027278473013bb9ce4022367deacd3f330813fef Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 7 Oct 2021 12:27:26 +0300 Subject: [PATCH 062/402] Add stable and front tracing to TD3 --- src/solvers/td3.ml | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/solvers/td3.ml b/src/solvers/td3.ml index a7e29fbf3b..9db589bcd2 100644 --- a/src/solvers/td3.ml +++ b/src/solvers/td3.ml @@ -92,6 +92,15 @@ module WP = let cache_sizes = ref [] in + let trace_called () = + if tracing then ( + let called_pretty () called = + HM.fold (fun x _ acc -> Pretty.dprintf "%a, %a" S.Var.pretty_trace x Pretty.insert acc) called Pretty.nil + in + trace "sol2" "called: %a\n" called_pretty called + ) + in + let add_infl y x = if tracing then trace "sol2" "add_infl %a %a\n" S.Var.pretty_trace y S.Var.pretty_trace x; HM.replace infl y (VS.add x (try HM.find infl y with Not_found -> VS.empty)); @@ -99,10 +108,12 @@ module WP = let add_sides y x = HM.replace sides y (VS.add x (try HM.find infl y with Not_found -> VS.empty)) in let rec destabilize ?(front=true) x = if tracing then trace "sol2" "destabilize %a\n" S.Var.pretty_trace x; + trace_called (); let w = HM.find_default infl x VS.empty in HM.replace infl x VS.empty; if front then ( VS.iter (fun y -> + if tracing then trace "sol2" "front add %a\n" S.Var.pretty_trace y; HM.replace destab_front y () ) w ) @@ -113,6 +124,7 @@ module WP = ) w ); VS.iter (fun y -> + if tracing then trace "sol2" "stable remove %a\n" S.Var.pretty_trace y; HM.remove stable y; if not (HM.mem called y) then destabilize ~front:false y ) w @@ -127,9 +139,11 @@ module WP = ) w false and solve ?(abort=true) x phase (changed: bool): bool = if tracing then trace "sol2" "solve %a, phase: %s, changed: %b, abort: %b, called: %b, stable: %b\n" S.Var.pretty_trace x (match phase with Widen -> "Widen" | Narrow -> "Narrow") changed abort (HM.mem called x) (HM.mem stable x); + trace_called (); init x; assert (S.system x <> None); if not (HM.mem called x || HM.mem stable x) then ( + if tracing then trace "sol2" "stable add %a\n" S.Var.pretty_trace x; HM.replace stable x (); HM.replace called x (); let wp = HM.mem wpoint x in @@ -197,10 +211,12 @@ module WP = (* If some side during eq made x unstable, then it should remain in destab_front. Otherwise recursive solve might prematurely abort it. *) if HM.mem destab_front x then ( + if tracing then trace "sol2" "front remove %a\n" S.Var.pretty_trace x; HM.remove destab_front x; if HM.mem destab_infl x then ( VS.iter (fun y -> if tracing then trace "sol2" "pushing front from %a to %a\n" S.Var.pretty_trace x S.Var.pretty_trace y; + if tracing then trace "sol2" "front add %a\n" S.Var.pretty_trace y; HM.replace destab_front y () ) (HM.find destab_infl x) ); @@ -218,6 +234,7 @@ module WP = (solve[@tailcall]) x Widen changed ) else ( if HM.mem destab_front x then ( + if tracing then trace "sol2" "front remove %a\n" S.Var.pretty_trace x; HM.remove destab_front x; if tracing then trace "sol2" "not pushing front from %a\n" S.Var.pretty_trace x; (* don't push front here *) @@ -225,6 +242,7 @@ module WP = ); if term && phase = Widen && HM.mem wpoint x then ( (* TODO: or use wp? *) if tracing then trace "sol2" "solve switching to narrow %a\n" S.Var.pretty_trace x; + if tracing then trace "sol2" "stable remove %a\n" S.Var.pretty_trace x; HM.remove stable x; (solve[@tailcall]) ~abort:false x Narrow changed ) else if not space && (not term || phase = Narrow) then ( (* this makes e.g. nested loops precise, ex. tests/regression/34-localization/01-nested.c - if we do not remove wpoint, the inner loop head will stay a wpoint and widen the outer loop variable. *) @@ -277,6 +295,7 @@ module WP = in let old = HM.find rho y in let tmp = op old d in + if tracing then trace "sol2" "stable add %a\n" S.Var.pretty_trace y; HM.replace stable y (); if not (S.Dom.leq tmp old) then ( (* if there already was a `side x y d` that changed rho[y] and now again, we make y a wpoint *) From 0adf31b4b2c2d24263f8d9f4d5b3052235167f3b Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 7 Oct 2021 12:31:20 +0300 Subject: [PATCH 063/402] Fix TD3 changed solve not pushing unstable front --- src/solvers/td3.ml | 32 ++++++++++++++++++-------------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/src/solvers/td3.ml b/src/solvers/td3.ml index 9db589bcd2..27894aabb4 100644 --- a/src/solvers/td3.ml +++ b/src/solvers/td3.ml @@ -115,7 +115,11 @@ module WP = VS.iter (fun y -> if tracing then trace "sol2" "front add %a\n" S.Var.pretty_trace y; HM.replace destab_front y () - ) w + ) w; + (* VS.iter (fun y -> + if tracing then trace "sol2" "front add %a\n" S.Var.pretty_trace y; + HM.replace destab_front y () + ) (HM.find_default destab_infl x VS.empty) *) ) else ( HM.replace destab_infl x (VS.union w (HM.find_default destab_infl x VS.empty)); @@ -207,21 +211,21 @@ module WP = update_var_event x old tmp; HM.replace rho x tmp; HM.replace called_changed x (); - if HM.mem stable x then ( - (* If some side during eq made x unstable, then it should remain in destab_front. - Otherwise recursive solve might prematurely abort it. *) - if HM.mem destab_front x then ( + if HM.mem destab_front x then ( + if HM.mem stable x then ( + (* If some side during eq made x unstable, then it should remain in destab_front. + Otherwise recursive solve might prematurely abort it. *) if tracing then trace "sol2" "front remove %a\n" S.Var.pretty_trace x; HM.remove destab_front x; - if HM.mem destab_infl x then ( - VS.iter (fun y -> - if tracing then trace "sol2" "pushing front from %a to %a\n" S.Var.pretty_trace x S.Var.pretty_trace y; - if tracing then trace "sol2" "front add %a\n" S.Var.pretty_trace y; - HM.replace destab_front y () - ) (HM.find destab_infl x) - ); - HM.remove destab_infl x - ) + ); + if HM.mem destab_infl x then ( + VS.iter (fun y -> + if tracing then trace "sol2" "pushing front from %a to %a\n" S.Var.pretty_trace x S.Var.pretty_trace y; + if tracing then trace "sol2" "front add %a\n" S.Var.pretty_trace y; + HM.replace destab_front y () + ) (HM.find destab_infl x) + ); + HM.remove destab_infl x ); destabilize x; (solve[@tailcall]) x phase true From 419b63e53a8e3ae2fa55e71e4647f4d0370db904 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 7 Oct 2021 12:47:49 +0300 Subject: [PATCH 064/402] Add exp.solver.td3.abort option --- src/solvers/td3.ml | 77 +++++++++++++++++++++++--------------------- src/util/defaults.ml | 1 + 2 files changed, 42 insertions(+), 36 deletions(-) diff --git a/src/solvers/td3.ml b/src/solvers/td3.ml index 27894aabb4..0cbb88f991 100644 --- a/src/solvers/td3.ml +++ b/src/solvers/td3.ml @@ -78,6 +78,7 @@ module WP = let wpoint = data.wpoint in let stable = data.stable in + let abort = GobConfig.get_bool "exp.solver.td3.abort" in let destab_infl = HM.create 10 in let destab_front = HM.create 10 in let destab_dep = HM.create 10 in @@ -111,21 +112,23 @@ module WP = trace_called (); let w = HM.find_default infl x VS.empty in HM.replace infl x VS.empty; - if front then ( - VS.iter (fun y -> - if tracing then trace "sol2" "front add %a\n" S.Var.pretty_trace y; - HM.replace destab_front y () - ) w; - (* VS.iter (fun y -> - if tracing then trace "sol2" "front add %a\n" S.Var.pretty_trace y; - HM.replace destab_front y () - ) (HM.find_default destab_infl x VS.empty) *) - ) - else ( - HM.replace destab_infl x (VS.union w (HM.find_default destab_infl x VS.empty)); - VS.iter (fun y -> - HM.replace destab_dep y (VS.add x (try HM.find destab_dep y with Not_found -> VS.empty)) - ) w + if abort then ( + if front then ( + VS.iter (fun y -> + if tracing then trace "sol2" "front add %a\n" S.Var.pretty_trace y; + HM.replace destab_front y () + ) w; + (* VS.iter (fun y -> + if tracing then trace "sol2" "front add %a\n" S.Var.pretty_trace y; + HM.replace destab_front y () + ) (HM.find_default destab_infl x VS.empty) *) + ) + else ( + HM.replace destab_infl x (VS.union w (HM.find_default destab_infl x VS.empty)); + VS.iter (fun y -> + HM.replace destab_dep y (VS.add x (try HM.find destab_dep y with Not_found -> VS.empty)) + ) w + ) ); VS.iter (fun y -> if tracing then trace "sol2" "stable remove %a\n" S.Var.pretty_trace y; @@ -141,8 +144,8 @@ module WP = HM.remove stable y; HM.mem called y || destabilize_vs y || b || was_stable && List.mem y vs ) w false - and solve ?(abort=true) x phase (changed: bool): bool = - if tracing then trace "sol2" "solve %a, phase: %s, changed: %b, abort: %b, called: %b, stable: %b\n" S.Var.pretty_trace x (match phase with Widen -> "Widen" | Narrow -> "Narrow") changed abort (HM.mem called x) (HM.mem stable x); + and solve ?(abortable=true) x phase (changed: bool): bool = + if tracing then trace "sol2" "solve %a, phase: %s, changed: %b, abortable: %b, called: %b, stable: %b\n" S.Var.pretty_trace x (match phase with Widen -> "Widen" | Narrow -> "Narrow") changed abortable (HM.mem called x) (HM.mem stable x); trace_called (); init x; assert (S.system x <> None); @@ -154,8 +157,8 @@ module WP = let old = HM.find rho x in let l = HM.create 10 in let eval' = - if tracing then trace "sol2" "eval' %a abort=%b destab_dep=%b\n" S.Var.pretty_trace x abort (HM.mem destab_dep x); - if HM.mem destab_dep x && abort then ( + if tracing then trace "sol2" "eval' %a abortable=%b destab_dep=%b\n" S.Var.pretty_trace x abortable (HM.mem destab_dep x); + if abort && abortable && HM.mem destab_dep x then ( let vs_pretty () vs = VS.fold (fun x acc -> Pretty.dprintf "%a, %a" S.Var.pretty_trace x Pretty.insert acc) vs Pretty.nil in @@ -211,21 +214,23 @@ module WP = update_var_event x old tmp; HM.replace rho x tmp; HM.replace called_changed x (); - if HM.mem destab_front x then ( - if HM.mem stable x then ( - (* If some side during eq made x unstable, then it should remain in destab_front. - Otherwise recursive solve might prematurely abort it. *) - if tracing then trace "sol2" "front remove %a\n" S.Var.pretty_trace x; - HM.remove destab_front x; - ); - if HM.mem destab_infl x then ( - VS.iter (fun y -> - if tracing then trace "sol2" "pushing front from %a to %a\n" S.Var.pretty_trace x S.Var.pretty_trace y; - if tracing then trace "sol2" "front add %a\n" S.Var.pretty_trace y; - HM.replace destab_front y () - ) (HM.find destab_infl x) - ); - HM.remove destab_infl x + if abort then ( + if HM.mem destab_front x then ( + if HM.mem stable x then ( + (* If some side during eq made x unstable, then it should remain in destab_front. + Otherwise recursive solve might prematurely abort it. *) + if tracing then trace "sol2" "front remove %a\n" S.Var.pretty_trace x; + HM.remove destab_front x; + ); + if HM.mem destab_infl x then ( + VS.iter (fun y -> + if tracing then trace "sol2" "pushing front from %a to %a\n" S.Var.pretty_trace x S.Var.pretty_trace y; + if tracing then trace "sol2" "front add %a\n" S.Var.pretty_trace y; + HM.replace destab_front y () + ) (HM.find destab_infl x) + ); + HM.remove destab_infl x + ) ); destabilize x; (solve[@tailcall]) x phase true @@ -237,7 +242,7 @@ module WP = if tracing then trace "sol2" "solve still unstable %a\n" S.Var.pretty_trace x; (solve[@tailcall]) x Widen changed ) else ( - if HM.mem destab_front x then ( + if abort && HM.mem destab_front x then ( if tracing then trace "sol2" "front remove %a\n" S.Var.pretty_trace x; HM.remove destab_front x; if tracing then trace "sol2" "not pushing front from %a\n" S.Var.pretty_trace x; @@ -248,7 +253,7 @@ module WP = if tracing then trace "sol2" "solve switching to narrow %a\n" S.Var.pretty_trace x; if tracing then trace "sol2" "stable remove %a\n" S.Var.pretty_trace x; HM.remove stable x; - (solve[@tailcall]) ~abort:false x Narrow changed + (solve[@tailcall]) ~abortable:false x Narrow changed ) else if not space && (not term || phase = Narrow) then ( (* this makes e.g. nested loops precise, ex. tests/regression/34-localization/01-nested.c - if we do not remove wpoint, the inner loop head will stay a wpoint and widen the outer loop variable. *) if tracing then trace "sol2" "solve removing wpoint %a (%b)\n" S.Var.pretty_trace x (HM.mem wpoint x); HM.remove wpoint x; diff --git a/src/util/defaults.ml b/src/util/defaults.ml index a59d937958..1d63d5a511 100644 --- a/src/util/defaults.ml +++ b/src/util/defaults.ml @@ -198,6 +198,7 @@ let _ = () ; reg Experimental "exp.solver.td3.space" "false" "Should the td3 solver only keep values at widening points?" ; reg Experimental "exp.solver.td3.space_cache" "true" "Should the td3-space solver cache values?" ; reg Experimental "exp.solver.td3.space_restore" "true" "Should the td3-space solver restore values for non-widening-points? Not needed for generating warnings, but needed for inspecting output!" + ; reg Experimental "exp.solver.td3.abort" "true" "TODO" ; reg Experimental "exp.solver.slr4.restart_count" "1" "How many times SLR4 is allowed to switch from restarting iteration to increasing iteration." ; reg Experimental "exp.fast_global_inits" "true" "Only generate one 'a[MyCFG.all_array_index_exp] = x' for all assignments a[...] = x for a global array a[n]." ; reg Experimental "exp.uninit-ptr-safe" "false" "Assume that uninitialized stack-allocated pointers may only point to variables not in the program or null." From bf121028aabd50262d482a67d6d825804f74ea13 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 7 Oct 2021 12:55:18 +0300 Subject: [PATCH 065/402] Add back TD3 space support without abort --- src/solvers/td3.ml | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/src/solvers/td3.ml b/src/solvers/td3.ml index 0cbb88f991..d21f80f492 100644 --- a/src/solvers/td3.ml +++ b/src/solvers/td3.ml @@ -68,7 +68,7 @@ module WP = let term = GobConfig.get_bool "exp.solver.td3.term" in let side_widen = GobConfig.get_string "exp.solver.td3.side_widen" in let space = GobConfig.get_bool "exp.solver.td3.space" in - (* let cache = GobConfig.get_bool "exp.solver.td3.space_cache" in *) + let cache = GobConfig.get_bool "exp.solver.td3.space_cache" in let called = HM.create 10 in let called_changed = HM.create 10 in @@ -278,7 +278,18 @@ module WP = if tracing then trace "sol2" "simple_solve %a (rhs: %b)\n" S.Var.pretty_trace y (S.system y <> None); if S.system y = None then (init y; (HM.find rho y, true (* TODO: ??? *))) else if HM.mem rho y || not space then (let changed = solve y Widen false in (HM.find rho y, changed)) else - failwith "space abort unimplemented" + if abort then failwith "space abort unimplemented" else + if HM.mem called y then (init y; HM.remove l y; (HM.find rho y, true (* TODO: ??? *))) else + (* if HM.mem called y then (init y; let y' = HM.find_default l y (S.Dom.bot ()) in HM.replace rho y y'; HM.remove l y; y') else *) + if cache && HM.mem l y then (HM.find l y, true (* TODO: ??? *)) + else ( + HM.replace called y (); + (* TODO: abort? *) + let tmp = eq y (fun z -> fst (eval l x z)) (side x) in + HM.remove called y; + if HM.mem rho y then (HM.remove l y; ignore (solve y Widen false); (HM.find rho y, true (* TODO: ??? *))) + else (if cache then HM.replace l y tmp; (tmp, true (* TODO: ??? *))) + ) and eval l x y: S.d * bool = if tracing then trace "sol2" "eval %a ## %a\n" S.Var.pretty_trace x S.Var.pretty_trace y; get_var_event y; From fb071a1b3302dd64c650c8138572afe9f42739fb Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 7 Oct 2021 15:02:34 +0300 Subject: [PATCH 066/402] Add TD3 abort verification by comparing with previous dep values --- src/solvers/td3.ml | 53 ++++++++++++++++++++++++++++++++++++++++++-- src/util/defaults.ml | 1 + 2 files changed, 52 insertions(+), 2 deletions(-) diff --git a/src/solvers/td3.ml b/src/solvers/td3.ml index d21f80f492..553f665945 100644 --- a/src/solvers/td3.ml +++ b/src/solvers/td3.ml @@ -83,6 +83,9 @@ module WP = let destab_front = HM.create 10 in let destab_dep = HM.create 10 in + let abort_verify = GobConfig.get_bool "exp.solver.td3.abort-verify" in + let prev_dep_vals = HM.create 10 in + let () = print_solver_stats := fun () -> Printf.printf "|rho|=%d\n|called|=%d\n|stable|=%d\n|infl|=%d\n|wpoint|=%d\n" (HM.length rho) (HM.length called) (HM.length stable) (HM.length infl) (HM.length wpoint); @@ -156,6 +159,9 @@ module WP = let wp = HM.mem wpoint x in let old = HM.find rho x in let l = HM.create 10 in + let prev_dep_vals_x = HM.find_default prev_dep_vals x (HM.create 0) in + let new_dep_vals_x = HM.create (HM.length prev_dep_vals_x) in + let bad_abort = ref false in let eval' = if tracing then trace "sol2" "eval' %a abortable=%b destab_dep=%b\n" S.Var.pretty_trace x abortable (HM.mem destab_dep x); if abort && abortable && HM.mem destab_dep x then ( @@ -165,16 +171,37 @@ module WP = let unasked_dep_x = ref (HM.find destab_dep x) in if tracing then trace "sol2" "eval' %a dep=%a\n" S.Var.pretty_trace x vs_pretty !unasked_dep_x; let all_dep_x_unchanged = ref true in + let all_dep_x_unchanged_verify = ref true in fun y -> let (d, changed) = eval l x y in if tracing then trace "sol2" "eval' %a asked %a changed=%b mem=%b\n" S.Var.pretty_trace x S.Var.pretty_trace y changed (VS.mem y !unasked_dep_x); + if abort_verify then ( + let prev_d = HM.find_default prev_dep_vals_x y (S.Dom.bot ()) in + if not (S.Dom.equal prev_d d) then ( + (* ignore (Pretty.eprintf "not changed did change: eval %a %a: old=%a new=%a\n" S.Var.pretty_trace x S.Var.pretty_trace y S.Dom.pretty prev_d S.Dom.pretty d); *) + if not changed then ( + ignore (Pretty.eprintf "not changed did change: eval %a %a: \nold=%a\n new=%a\n" S.Var.pretty_trace x S.Var.pretty_trace y S.Dom.pretty prev_d S.Dom.pretty d) + ); + (* assert false *) + all_dep_x_unchanged_verify := false + ) + ); if VS.mem y !unasked_dep_x then ( unasked_dep_x := VS.remove y !unasked_dep_x; if changed then all_dep_x_unchanged := false; if tracing then trace "sol2" "eval' %a asked %a checking abort unasked=%a all_unchanged=%b front=%b\n" S.Var.pretty_trace x S.Var.pretty_trace y vs_pretty !unasked_dep_x !all_dep_x_unchanged (HM.mem destab_front x); - if VS.is_empty !unasked_dep_x && !all_dep_x_unchanged && not (HM.mem destab_front x) then (* must check front here, because each eval might change it for x *) + let should_abort = VS.is_empty !unasked_dep_x && !all_dep_x_unchanged && not (HM.mem destab_front x) in (* must check front here, because each eval might change it for x *) + let should_abort_verify = !all_dep_x_unchanged_verify in + if should_abort then ( + if abort_verify && not should_abort_verify then ( + ignore (Pretty.eprintf "should not abort %a\n" S.Var.pretty_trace x); + bad_abort := true; + (* assert false; *) + ); + (* assert (should_abort_verify); *) raise AbortEq + ) ); d ) @@ -183,6 +210,16 @@ module WP = let (d, changed) = eval l x y in d in + let eval' = + if abort then ( + fun y -> + let d = eval' y in + HM.replace new_dep_vals_x y d; + d + ) + else + eval' + in let tmp = try eq x eval' (side x) @@ -190,8 +227,16 @@ module WP = abort_rhs_event x; if tracing then trace "sol2" "eq aborted %a\n" S.Var.pretty_trace x; HM.remove destab_dep x; (* TODO: safe to remove here? doesn't prevent some aborts? *) + HM.iter (fun y d -> + HM.replace new_dep_vals_x y d; + ) prev_dep_vals_x; old in + if !bad_abort then ( + ignore (Pretty.eprintf "bad abort %a: \n%a\n vs \n%a\n" S.Var.pretty_trace x S.Dom.pretty old S.Dom.pretty tmp); + assert false; + ); + (* HM.replace prev_dep_vals x new_dep_vals_x; *) (* TODO: why not always? *) (* let tmp = if GobConfig.get_bool "ana.opt.hashcons" then S.Dom.join (S.Dom.bot ()) tmp else tmp in (* Call hashcons via dummy join so that the tag of the rhs value is up to date. Otherwise we might get the same value as old, but still with a different tag (because no lattice operation was called after a change), and since Printable.HConsed.equal just looks at the tag, we would uneccessarily destabilize below. Seems like this does not happen. *) *) if tracing then trace "sol" "Var: %a\n" S.Var.pretty_trace x ; if tracing then trace "sol" "Contrib:%a\n" S.Dom.pretty tmp; @@ -213,6 +258,7 @@ module WP = if tracing then trace "sol" "Changed\n"; update_var_event x old tmp; HM.replace rho x tmp; + HM.replace prev_dep_vals x new_dep_vals_x; HM.replace called_changed x (); if abort then ( if HM.mem destab_front x then ( @@ -257,10 +303,13 @@ module WP = ) else if not space && (not term || phase = Narrow) then ( (* this makes e.g. nested loops precise, ex. tests/regression/34-localization/01-nested.c - if we do not remove wpoint, the inner loop head will stay a wpoint and widen the outer loop variable. *) if tracing then trace "sol2" "solve removing wpoint %a (%b)\n" S.Var.pretty_trace x (HM.mem wpoint x); HM.remove wpoint x; + HM.replace prev_dep_vals x new_dep_vals_x; changed ) - else + else ( + HM.replace prev_dep_vals x new_dep_vals_x; changed + ) ) ) ) diff --git a/src/util/defaults.ml b/src/util/defaults.ml index 1d63d5a511..341dfb832b 100644 --- a/src/util/defaults.ml +++ b/src/util/defaults.ml @@ -199,6 +199,7 @@ let _ = () ; reg Experimental "exp.solver.td3.space_cache" "true" "Should the td3-space solver cache values?" ; reg Experimental "exp.solver.td3.space_restore" "true" "Should the td3-space solver restore values for non-widening-points? Not needed for generating warnings, but needed for inspecting output!" ; reg Experimental "exp.solver.td3.abort" "true" "TODO" + ; reg Experimental "exp.solver.td3.abort-verify" "true" "TODO" ; reg Experimental "exp.solver.slr4.restart_count" "1" "How many times SLR4 is allowed to switch from restarting iteration to increasing iteration." ; reg Experimental "exp.fast_global_inits" "true" "Only generate one 'a[MyCFG.all_array_index_exp] = x' for all assignments a[...] = x for a global array a[n]." ; reg Experimental "exp.uninit-ptr-safe" "false" "Assume that uninitialized stack-allocated pointers may only point to variables not in the program or null." From 9426674a4c837aa43343268501890d7e7041b729 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 7 Oct 2021 15:08:04 +0300 Subject: [PATCH 067/402] Deduplicate new prev_dep_vals setting in TD3 abort verify --- src/solvers/td3.ml | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/solvers/td3.ml b/src/solvers/td3.ml index 553f665945..7e9682315b 100644 --- a/src/solvers/td3.ml +++ b/src/solvers/td3.ml @@ -236,7 +236,7 @@ module WP = ignore (Pretty.eprintf "bad abort %a: \n%a\n vs \n%a\n" S.Var.pretty_trace x S.Dom.pretty old S.Dom.pretty tmp); assert false; ); - (* HM.replace prev_dep_vals x new_dep_vals_x; *) (* TODO: why not always? *) + HM.replace prev_dep_vals x new_dep_vals_x; (* let tmp = if GobConfig.get_bool "ana.opt.hashcons" then S.Dom.join (S.Dom.bot ()) tmp else tmp in (* Call hashcons via dummy join so that the tag of the rhs value is up to date. Otherwise we might get the same value as old, but still with a different tag (because no lattice operation was called after a change), and since Printable.HConsed.equal just looks at the tag, we would uneccessarily destabilize below. Seems like this does not happen. *) *) if tracing then trace "sol" "Var: %a\n" S.Var.pretty_trace x ; if tracing then trace "sol" "Contrib:%a\n" S.Dom.pretty tmp; @@ -258,7 +258,6 @@ module WP = if tracing then trace "sol" "Changed\n"; update_var_event x old tmp; HM.replace rho x tmp; - HM.replace prev_dep_vals x new_dep_vals_x; HM.replace called_changed x (); if abort then ( if HM.mem destab_front x then ( @@ -303,13 +302,10 @@ module WP = ) else if not space && (not term || phase = Narrow) then ( (* this makes e.g. nested loops precise, ex. tests/regression/34-localization/01-nested.c - if we do not remove wpoint, the inner loop head will stay a wpoint and widen the outer loop variable. *) if tracing then trace "sol2" "solve removing wpoint %a (%b)\n" S.Var.pretty_trace x (HM.mem wpoint x); HM.remove wpoint x; - HM.replace prev_dep_vals x new_dep_vals_x; changed ) - else ( - HM.replace prev_dep_vals x new_dep_vals_x; + else changed - ) ) ) ) From 281b8fb351c0832189501e14214f02263e7d1890 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 7 Oct 2021 15:10:52 +0300 Subject: [PATCH 068/402] Remove bad_abort flag from TD3 abort verify --- src/solvers/td3.ml | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/src/solvers/td3.ml b/src/solvers/td3.ml index 7e9682315b..8fb974470a 100644 --- a/src/solvers/td3.ml +++ b/src/solvers/td3.ml @@ -161,7 +161,6 @@ module WP = let l = HM.create 10 in let prev_dep_vals_x = HM.find_default prev_dep_vals x (HM.create 0) in let new_dep_vals_x = HM.create (HM.length prev_dep_vals_x) in - let bad_abort = ref false in let eval' = if tracing then trace "sol2" "eval' %a abortable=%b destab_dep=%b\n" S.Var.pretty_trace x abortable (HM.mem destab_dep x); if abort && abortable && HM.mem destab_dep x then ( @@ -196,8 +195,7 @@ module WP = if should_abort then ( if abort_verify && not should_abort_verify then ( ignore (Pretty.eprintf "should not abort %a\n" S.Var.pretty_trace x); - bad_abort := true; - (* assert false; *) + assert false; ); (* assert (should_abort_verify); *) raise AbortEq @@ -232,10 +230,6 @@ module WP = ) prev_dep_vals_x; old in - if !bad_abort then ( - ignore (Pretty.eprintf "bad abort %a: \n%a\n vs \n%a\n" S.Var.pretty_trace x S.Dom.pretty old S.Dom.pretty tmp); - assert false; - ); HM.replace prev_dep_vals x new_dep_vals_x; (* let tmp = if GobConfig.get_bool "ana.opt.hashcons" then S.Dom.join (S.Dom.bot ()) tmp else tmp in (* Call hashcons via dummy join so that the tag of the rhs value is up to date. Otherwise we might get the same value as old, but still with a different tag (because no lattice operation was called after a change), and since Printable.HConsed.equal just looks at the tag, we would uneccessarily destabilize below. Seems like this does not happen. *) *) if tracing then trace "sol" "Var: %a\n" S.Var.pretty_trace x ; From 0b4eb683c0253d28bf977de34000feb91c0cc89e Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 7 Oct 2021 16:35:48 +0300 Subject: [PATCH 069/402] Refactor TD3 abort verify --- src/solvers/td3.ml | 52 +++++++++++++++++++++------------------------- 1 file changed, 24 insertions(+), 28 deletions(-) diff --git a/src/solvers/td3.ml b/src/solvers/td3.ml index 8fb974470a..8200425c74 100644 --- a/src/solvers/td3.ml +++ b/src/solvers/td3.ml @@ -104,6 +104,9 @@ module WP = trace "sol2" "called: %a\n" called_pretty called ) in + let vs_pretty () vs = + VS.fold (fun x acc -> Pretty.dprintf "%a, %a" S.Var.pretty_trace x Pretty.insert acc) vs Pretty.nil + in let add_infl y x = if tracing then trace "sol2" "add_infl %a %a\n" S.Var.pretty_trace y S.Var.pretty_trace x; @@ -159,14 +162,10 @@ module WP = let wp = HM.mem wpoint x in let old = HM.find rho x in let l = HM.create 10 in - let prev_dep_vals_x = HM.find_default prev_dep_vals x (HM.create 0) in - let new_dep_vals_x = HM.create (HM.length prev_dep_vals_x) in + let prev_dep_vals_x = HM.find_default prev_dep_vals x (HM.create 0) in (* used by abort_verify *) let eval' = if tracing then trace "sol2" "eval' %a abortable=%b destab_dep=%b\n" S.Var.pretty_trace x abortable (HM.mem destab_dep x); if abort && abortable && HM.mem destab_dep x then ( - let vs_pretty () vs = - VS.fold (fun x acc -> Pretty.dprintf "%a, %a" S.Var.pretty_trace x Pretty.insert acc) vs Pretty.nil - in let unasked_dep_x = ref (HM.find destab_dep x) in if tracing then trace "sol2" "eval' %a dep=%a\n" S.Var.pretty_trace x vs_pretty !unasked_dep_x; let all_dep_x_unchanged = ref true in @@ -177,12 +176,11 @@ module WP = if abort_verify then ( let prev_d = HM.find_default prev_dep_vals_x y (S.Dom.bot ()) in if not (S.Dom.equal prev_d d) then ( - (* ignore (Pretty.eprintf "not changed did change: eval %a %a: old=%a new=%a\n" S.Var.pretty_trace x S.Var.pretty_trace y S.Dom.pretty prev_d S.Dom.pretty d); *) - if not changed then ( + (* TODO: this is not a bug? change might be covered by destab_front *) + (* if not changed then ( ignore (Pretty.eprintf "not changed did change: eval %a %a: \nold=%a\n new=%a\n" S.Var.pretty_trace x S.Var.pretty_trace y S.Dom.pretty prev_d S.Dom.pretty d) - ); - (* assert false *) - all_dep_x_unchanged_verify := false + ); *) + all_dep_x_unchanged_verify := false; ) ); if VS.mem y !unasked_dep_x then ( @@ -194,10 +192,8 @@ module WP = let should_abort_verify = !all_dep_x_unchanged_verify in if should_abort then ( if abort_verify && not should_abort_verify then ( - ignore (Pretty.eprintf "should not abort %a\n" S.Var.pretty_trace x); - assert false; + failwith (Pretty.sprint ~width:max_int (Pretty.dprintf "TD3 abort verify: should not abort %a" S.Var.pretty_trace x)); ); - (* assert (should_abort_verify); *) raise AbortEq ) ); @@ -208,29 +204,29 @@ module WP = let (d, changed) = eval l x y in d in - let eval' = - if abort then ( - fun y -> - let d = eval' y in - HM.replace new_dep_vals_x y d; - d - ) - else - eval' - in let tmp = try - eq x eval' (side x) + if abort && abort_verify then ( + (* collect dep vals for x *) + let new_dep_vals_x = HM.create (HM.length prev_dep_vals_x) in + let eval' y = + let d = eval' y in + HM.replace new_dep_vals_x y d; + d + in + let tmp = eq x eval' (side x) in + HM.replace prev_dep_vals x new_dep_vals_x; + tmp + ) + else + eq x eval' (side x) with AbortEq -> abort_rhs_event x; if tracing then trace "sol2" "eq aborted %a\n" S.Var.pretty_trace x; HM.remove destab_dep x; (* TODO: safe to remove here? doesn't prevent some aborts? *) - HM.iter (fun y d -> - HM.replace new_dep_vals_x y d; - ) prev_dep_vals_x; + (* prev_dep_vals remain the same *) old in - HM.replace prev_dep_vals x new_dep_vals_x; (* let tmp = if GobConfig.get_bool "ana.opt.hashcons" then S.Dom.join (S.Dom.bot ()) tmp else tmp in (* Call hashcons via dummy join so that the tag of the rhs value is up to date. Otherwise we might get the same value as old, but still with a different tag (because no lattice operation was called after a change), and since Printable.HConsed.equal just looks at the tag, we would uneccessarily destabilize below. Seems like this does not happen. *) *) if tracing then trace "sol" "Var: %a\n" S.Var.pretty_trace x ; if tracing then trace "sol" "Contrib:%a\n" S.Dom.pretty tmp; From e6a4953517ee4dcd60573fbe8846468b556a93df Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Fri, 8 Oct 2021 14:22:51 +0300 Subject: [PATCH 070/402] Extract IncrWarn postsolver in TD3 --- src/solvers/td3.ml | 51 +++++++++++++++++++++++++++++++++------------- 1 file changed, 37 insertions(+), 14 deletions(-) diff --git a/src/solvers/td3.ml b/src/solvers/td3.ml index 51a7f25155..95e50d6126 100644 --- a/src/solvers/td3.ml +++ b/src/solvers/td3.ml @@ -67,12 +67,12 @@ module WP = type phase = Widen | Narrow + let current_var = ref None + module S = struct include S - let current_var = ref None - let system x = match S.system x with | None -> None @@ -421,7 +421,41 @@ module WP = HM.filteri_inplace (fun x _ -> HM.mem superstable x) var_messages; - let module Post = PostSolver.MakeList (PostSolver.ListArgFromStdArg (S) (HM) (Arg)) in + let module IncrWarn: PostSolver.S with module S = S and module VH = HM = + struct + include PostSolver.Warn (S) (HM) + + let init () = + init (); (* enable warning like standard Warn *) + + (* replay superstable messages *) + HM.iter (fun _ m -> + Messages.add m + ) var_messages; + + (* hook to collect new messages *) + Messages.Table.add_hook := (fun m -> + match !current_var with + | Some x -> HM.add var_messages x m + | None -> () + ); + end + in + let module MakeListArg = + struct + module Arg = + struct + include Arg + let should_warn = false (* disable standard Warn in favor of IncrWarn *) + end + include PostSolver.ListArgFromStdArg (S) (HM) (Arg) + + let postsolvers = (module IncrWarn: M) :: postsolvers + end + in + + let module Post = PostSolver.MakeList (MakeListArg) in + begin match Post.postsolver_opt with | None -> () | Some (module PS) -> @@ -431,7 +465,6 @@ module WP = if get_bool "dbg.verbose" then print_endline "Postsolving\n"; - let module OutS = S in let module StartS = struct include S @@ -443,16 +476,6 @@ module WP = Goblintutil.postsolving := true; PS.init (); - HM.iter (fun _ m -> - Messages.add m - ) var_messages; - - Messages.Table.add_hook := (fun m -> - match !OutS.current_var with - | Some x -> HM.add var_messages x m - | None -> () - ); - let reachable = HM.copy superstable in (* consider superstable reached: stop recursion (evaluation) and keep from being pruned *) let rec one_var x = if not (HM.mem reachable x) then ( From bd1234340356105451fafb208822caf8ccc85c71 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Fri, 8 Oct 2021 14:46:07 +0300 Subject: [PATCH 071/402] Extract and generalize incremental postsolver from TD3 --- src/solvers/postSolver.ml | 49 +++++++++++++++++++++++++++------ src/solvers/td3.ml | 58 ++++----------------------------------- 2 files changed, 45 insertions(+), 62 deletions(-) diff --git a/src/solvers/postSolver.ml b/src/solvers/postSolver.ml index 56b70941c0..c2c2838f4b 100644 --- a/src/solvers/postSolver.ml +++ b/src/solvers/postSolver.ml @@ -155,9 +155,15 @@ struct | Some f, Some d -> Some (fun get set -> S.Dom.join (f get set) d) end -(** Make complete postsolving function from postsolver. - This is generic and non-incremental. *) -module Make (PS: S) = +(** Postsolver for incremental. *) +module type IncrS = +sig + include S + val init_reachable: vh:S.Dom.t VH.t -> unit VH.t +end + +(** Make incremental postsolving function from incremental postsolver. *) +module MakeIncr (PS: IncrS) = struct module S = PS.S module VH = PS.VH @@ -177,7 +183,7 @@ struct Goblintutil.postsolving := true; PS.init (); - let reachable = VH.create (VH.length vh) in + let reachable = PS.init_reachable ~vh in let rec one_var x = if not (VH.mem reachable x) then ( VH.replace reachable x (); @@ -217,10 +223,17 @@ sig val postsolvers: (module M) list end -(** Make complete postsolving function from list of postsolvers. - If list is empty, no postsolving is performed. - This is generic and non-incremental. *) -module MakeList (Arg: MakeListArg) = +(** List of postsolvers for incremental. *) +module type MakeIncrListArg = +sig + include MakeListArg + + val init_reachable: vh:S.Dom.t VH.t -> unit VH.t +end + +(** Make incremental postsolving function from incremental list of postsolvers. + If list is empty, no postsolving is performed. *) +module MakeIncrList (Arg: MakeIncrListArg) = struct module S = Arg.S module VH = Arg.VH @@ -238,10 +251,28 @@ struct match postsolver_opt with | None -> () | Some (module PS) -> - let module M = Make (PS) in + let module IncrPS = + struct + include PS + let init_reachable = Arg.init_reachable + end + in + let module M = MakeIncr (IncrPS) in M.post xs vs vh end +(** Make complete (non-incremental) postsolving function from list of postsolvers. + If list is empty, no postsolving is performed. *) +module MakeList (Arg: MakeListArg) = +struct + module IncrArg = + struct + include Arg + let init_reachable ~vh = VH.create (VH.length vh) + end + include MakeIncrList (IncrArg) +end + (** Standard postsolver options. *) module type MakeStdArg = sig diff --git a/src/solvers/td3.ml b/src/solvers/td3.ml index 95e50d6126..1c64b8702e 100644 --- a/src/solvers/td3.ml +++ b/src/solvers/td3.ml @@ -441,7 +441,7 @@ module WP = ); end in - let module MakeListArg = + let module MakeIncrListArg = struct module Arg = struct @@ -451,62 +451,14 @@ module WP = include PostSolver.ListArgFromStdArg (S) (HM) (Arg) let postsolvers = (module IncrWarn: M) :: postsolvers + + let init_reachable ~vh = HM.copy superstable (* consider superstable reached: stop recursion (evaluation) and keep from being pruned *) end in - let module Post = PostSolver.MakeList (MakeListArg) in - - begin match Post.postsolver_opt with - | None -> () - | Some (module PS) -> - let open GobConfig in - - let post xs vs vh = - if get_bool "dbg.verbose" then - print_endline "Postsolving\n"; - - let module StartS = - struct - include S - let starts = xs - end - in - let module S = PostSolver.EqConstrSysFromStartEqConstrSys (StartS) in - - Goblintutil.postsolving := true; - PS.init (); - - let reachable = HM.copy superstable in (* consider superstable reached: stop recursion (evaluation) and keep from being pruned *) - let rec one_var x = - if not (HM.mem reachable x) then ( - HM.replace reachable x (); - Option.may (one_constraint x) (S.system x) - ) - and one_constraint x f = - let get y = - one_var y; - try HM.find vh y with Not_found -> S.Dom.bot () - in - let set y d = - PS.one_side ~vh ~x ~y ~d; - (* check before recursing *) - one_var y - in - let rhs = f get set in - PS.one_constraint ~vh ~x ~rhs - in - List.iter one_var vs; - - PS.finalize ~vh ~reachable; - Goblintutil.postsolving := false - in - - let post xs vs vh = - Stats.time "postsolver" (post xs vs) vh - in + let module Post = PostSolver.MakeIncrList (MakeIncrListArg) in - post st vs rho (* TODO: add side_infl postsolver *) - end; + Post.post st vs rho; (* TODO: add side_infl postsolver *) {st; infl; sides; rho; wpoint; stable; var_messages} From 164b9d2afc2a00f86c89c5d9c92d94658626a300 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 13 Oct 2021 10:31:38 +0300 Subject: [PATCH 072/402] Add option incremental.verify This allows disabling incremental verify and doing full verify during incremental load. It is useful for getting race warnings. --- src/solvers/td3.ml | 20 +++++++++++++++----- src/util/defaults.ml | 1 + 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/src/solvers/td3.ml b/src/solvers/td3.ml index 1c64b8702e..31a497c2a6 100644 --- a/src/solvers/td3.ml +++ b/src/solvers/td3.ml @@ -102,6 +102,7 @@ module WP = let wpoint = data.wpoint in let stable = data.stable in + let incr_verify = GobConfig.get_bool "incremental.verify" in (* In incremental load, initially stable nodes, which are never destabilized. These don't have to be re-verified and warnings can be reused. *) let superstable = HM.copy stable in @@ -419,7 +420,10 @@ module WP = print_newline (); ); - HM.filteri_inplace (fun x _ -> HM.mem superstable x) var_messages; + if incr_verify then + HM.filteri_inplace (fun x _ -> HM.mem superstable x) var_messages + else + HM.clear var_messages; let module IncrWarn: PostSolver.S with module S = S and module VH = HM = struct @@ -429,9 +433,11 @@ module WP = init (); (* enable warning like standard Warn *) (* replay superstable messages *) - HM.iter (fun _ m -> - Messages.add m - ) var_messages; + if incr_verify then ( + HM.iter (fun _ m -> + Messages.add m + ) var_messages; + ); (* hook to collect new messages *) Messages.Table.add_hook := (fun m -> @@ -452,7 +458,11 @@ module WP = let postsolvers = (module IncrWarn: M) :: postsolvers - let init_reachable ~vh = HM.copy superstable (* consider superstable reached: stop recursion (evaluation) and keep from being pruned *) + let init_reachable ~vh = + if incr_verify then + HM.copy superstable (* consider superstable reached: stop recursion (evaluation) and keep from being pruned *) + else + HM.create (HM.length vh) end in diff --git a/src/util/defaults.ml b/src/util/defaults.ml index a59d937958..da5d29d47b 100644 --- a/src/util/defaults.ml +++ b/src/util/defaults.ml @@ -152,6 +152,7 @@ let _ = () ; reg Incremental "incremental.save" "false" "Store incremental analysis results." ; reg Incremental "incremental.stable" "true" "Reuse the stable set and selectively destabilize it (recommended)." ; reg Incremental "incremental.wpoint" "false" "Reuse the wpoint set (not recommended). Reusing the wpoint will combine existing results at previous widening points." + ; reg Incremental "incremental.verify" "true" "TODO" (* {4 category [Semantics]} *) let _ = () From 758b2ce57e0bb5ac91dc90a80571f42009b59711 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 14 Oct 2021 12:43:04 +0300 Subject: [PATCH 073/402] Fix missing incremental warnings due to var_messages not being relifted --- src/solvers/td3.ml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/solvers/td3.ml b/src/solvers/td3.ml index d1327ac8d1..1135136577 100644 --- a/src/solvers/td3.ml +++ b/src/solvers/td3.ml @@ -662,7 +662,11 @@ module WP = ) data.infl; data.infl <- infl'; data.st <- List.map (fun (k, v) -> S.Var.relift k, S.Dom.relift v) data.st; - (* TODO: relift var_messages? *) + let var_messages' = HM.create (HM.length data.var_messages) in + HM.iter (fun k v -> + HM.add var_messages' (S.Var.relift k) v (* var_messages contains duplicate keys, so must add not replace! *) + ) data.var_messages; + data.var_messages <- var_messages'; ); if not reuse_stable then ( print_endline "Destabilizing everything!"; From 9437478a9a6815c8be9f5567fe57d8fd6374b116 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 14 Oct 2021 12:43:27 +0300 Subject: [PATCH 074/402] Fix destabilize_with_side not removing from superstable in TD3 --- src/solvers/td3.ml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/solvers/td3.ml b/src/solvers/td3.ml index 1135136577..5c6372d929 100644 --- a/src/solvers/td3.ml +++ b/src/solvers/td3.ml @@ -339,6 +339,7 @@ module WP = VS.iter (fun y -> if tracing then trace "sol2" "destabilize_with_side %a side_dep %a\n" S.Var.pretty_trace x S.Var.pretty_trace y; HM.remove stable y; + HM.remove superstable y; destabilize_with_side y ) w ); @@ -349,6 +350,7 @@ module WP = VS.iter (fun y -> if tracing then trace "sol2" "destabilize_with_side %a infl %a\n" S.Var.pretty_trace x S.Var.pretty_trace y; HM.remove stable y; + HM.remove superstable y; destabilize_with_side y ) w; @@ -359,6 +361,7 @@ module WP = VS.iter (fun y -> if tracing then trace "sol2" "destabilize_with_side %a side_infl %a\n" S.Var.pretty_trace x S.Var.pretty_trace y; HM.remove stable y; + HM.remove superstable y; destabilize_with_side y ) w in From b3761005e1bcdcc11051bf45e90a00b1f33cb82e Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Mon, 18 Oct 2021 16:28:28 +0300 Subject: [PATCH 075/402] Add minimal creduced case where TD3 abort fails its verify --- .../29-svcomp/27-td3-front-via-destab-infl.c | 42 +++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 tests/regression/29-svcomp/27-td3-front-via-destab-infl.c diff --git a/tests/regression/29-svcomp/27-td3-front-via-destab-infl.c b/tests/regression/29-svcomp/27-td3-front-via-destab-infl.c new file mode 100644 index 0000000000..d39cb15046 --- /dev/null +++ b/tests/regression/29-svcomp/27-td3-front-via-destab-infl.c @@ -0,0 +1,42 @@ +// PARAM: --set ana.activated[+] var_eq --set ana.activated[+] symb_locks --set ana.activated[+] region --enable ana.sv-comp.enabled --set ana.specification "CHECK( init(main()), LTL(G ! call(reach_error())) )" + +// creduced from ldv-linux-4.2-rc1/linux-4.2-rc1.tar.xz-43_2a-drivers--scsi--qla4xxx--qla4xxx.ko-entry_point.cil.out.i +// this program and params are really minimal, which produced a TD3 abort verify error, so don't simplify + +int a; + +void c(); + +void b() { + c(); +} + +unsigned e() { + int d; + if (d) + c(); + return; +} + +void c() { + int f; + unsigned g = 0; + + do { + g = e(); + if (a) + return; + + do { + f++; + } while (f); + + } while (g); + + b(); +} + +int main() { + b(); + return 0; +} From e99acabb46a5d11e03d7aba477b5c9939ae5b268 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Mon, 18 Oct 2021 16:32:29 +0300 Subject: [PATCH 076/402] Add more TD3 tracing --- src/framework/analyses.ml | 1 + src/solvers/td3.ml | 6 ++++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/framework/analyses.ml b/src/framework/analyses.ml index d1a56f1aef..40f2b5fbc4 100644 --- a/src/framework/analyses.ml +++ b/src/framework/analyses.ml @@ -54,6 +54,7 @@ struct let pretty_trace () ((n,c) as x) = if get_bool "dbg.trace.context" then dprintf "(%a, %a) on %a \n" Node.pretty_trace n LD.pretty c CilType.Location.pretty (getLocation x) + (* if get_bool "dbg.trace.context" then dprintf "(%a, %d) on %a" Node.pretty_trace n (LD.tag c) CilType.Location.pretty (getLocation x) *) else dprintf "%a on %a" Node.pretty_trace n CilType.Location.pretty (getLocation x) let printXml f (n,c) = diff --git a/src/solvers/td3.ml b/src/solvers/td3.ml index 8200425c74..d289ac521d 100644 --- a/src/solvers/td3.ml +++ b/src/solvers/td3.ml @@ -99,9 +99,9 @@ module WP = let trace_called () = if tracing then ( let called_pretty () called = - HM.fold (fun x _ acc -> Pretty.dprintf "%a, %a" S.Var.pretty_trace x Pretty.insert acc) called Pretty.nil + HM.fold (fun x _ acc -> Pretty.dprintf "%a\n %a" S.Var.pretty_trace x Pretty.insert acc) called Pretty.nil in - trace "sol2" "called: %a\n" called_pretty called + trace "sol2" "called:\n %a\n" called_pretty called ) in let vs_pretty () vs = @@ -181,6 +181,7 @@ module WP = ignore (Pretty.eprintf "not changed did change: eval %a %a: \nold=%a\n new=%a\n" S.Var.pretty_trace x S.Var.pretty_trace y S.Dom.pretty prev_d S.Dom.pretty d) ); *) all_dep_x_unchanged_verify := false; + if tracing then trace "sol2" "eval' %a asked %a abort %B verify\n prev=%a\n now=%a\n" S.Var.pretty_trace x S.Var.pretty_trace y (HM.mem prev_dep_vals_x y) S.Dom.pretty prev_d S.Dom.pretty d; ) ); if VS.mem y !unasked_dep_x then ( @@ -331,6 +332,7 @@ module WP = if HM.mem called y then HM.replace wpoint y (); let tmp = simple_solve l x y in if HM.mem rho y then add_infl y x; + if tracing then trace "sol2" "eval %a ## %a -> %a\n" S.Var.pretty_trace x S.Var.pretty_trace y S.Dom.pretty (fst tmp); tmp and side x y d = (* side from x to y; only to variables y w/o rhs; x only used for trace *) if tracing then trace "sol2" "side to %a (wpx: %b) from %a ## value: %a\n" S.Var.pretty_trace y (HM.mem wpoint y) S.Var.pretty_trace x S.Dom.pretty d; From 234c4c7711a273992999b38c0dc0fc6e0f8d5664 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Mon, 18 Oct 2021 16:34:23 +0300 Subject: [PATCH 077/402] Reuse commented out destab_infl front code to fix TD3 abort --- src/solvers/td3.ml | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/solvers/td3.ml b/src/solvers/td3.ml index d289ac521d..6ea7a5029d 100644 --- a/src/solvers/td3.ml +++ b/src/solvers/td3.ml @@ -121,13 +121,15 @@ module WP = if abort then ( if front then ( VS.iter (fun y -> - if tracing then trace "sol2" "front add %a\n" S.Var.pretty_trace y; + if tracing then trace "sol2" "front add %a (infl)\n" S.Var.pretty_trace y; HM.replace destab_front y () ) w; - (* VS.iter (fun y -> - if tracing then trace "sol2" "front add %a\n" S.Var.pretty_trace y; + (* Also add front via destab_infl in case infl has already been removed by previous destabilize. + This fixes 29-svcomp/27-td3-front-via-destab-infl. *) + VS.iter (fun y -> + if tracing then trace "sol2" "front add %a (destab_infl)\n" S.Var.pretty_trace y; HM.replace destab_front y () - ) (HM.find_default destab_infl x VS.empty) *) + ) (HM.find_default destab_infl x VS.empty) ) else ( HM.replace destab_infl x (VS.union w (HM.find_default destab_infl x VS.empty)); From f9def12e5b3e473b0a24882a4625d81dc6c386f5 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Mon, 18 Oct 2021 13:58:31 +0000 Subject: [PATCH 078/402] Add creduce script for TD3 abort verify failure --- scripts/creduce-abort-verify.sh | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100755 scripts/creduce-abort-verify.sh diff --git a/scripts/creduce-abort-verify.sh b/scripts/creduce-abort-verify.sh new file mode 100755 index 0000000000..8e5ddc9a64 --- /dev/null +++ b/scripts/creduce-abort-verify.sh @@ -0,0 +1,19 @@ +#!/usr/bin/env bash + +set -e + +gcc -c -Werror=implicit-function-declaration ./abort-verify.c + +GOBLINTDIR="/mnt/goblint-svcomp/sv-comp/goblint" +OPTS="--conf $GOBLINTDIR/conf/svcomp.json --enable exp.solver.td3.abort --enable exp.solver.td3.abort-verify --sets ana.specification /mnt/goblint-svcomp/benchexec/sv-benchmarks/c/properties/unreach-call.prp --sets exp.architecture 64bit ./abort-verify.c" +INTERESTING="TD3 abort verify: should not abort" +OUTDIR="creduce-abort-verify" + + +mkdir -p $OUTDIR + +LOG="$OUTDIR/out.log" +$GOBLINTDIR/goblint $OPTS -v --enable dbg.debug &> $LOG || true +grep -F "Function definition missing" $LOG && exit 1 + +grep -F "$INTERESTING" $LOG From 091cdbe0c688392d9c50a968cbd5fdb665a818bc Mon Sep 17 00:00:00 2001 From: Vesal Vojdani Date: Wed, 20 Oct 2021 12:59:01 +0300 Subject: [PATCH 079/402] Relift side_infl and side_dep. --- src/solvers/td3.ml | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/solvers/td3.ml b/src/solvers/td3.ml index f60c56e869..351ecf36f3 100644 --- a/src/solvers/td3.ml +++ b/src/solvers/td3.ml @@ -664,6 +664,16 @@ module WP = HM.replace infl' (S.Var.relift k) (VS.map S.Var.relift v) ) data.infl; data.infl <- infl'; + let side_infl' = HM.create (HM.length data.side_infl) in + HM.iter (fun k v -> + HM.replace side_infl' (S.Var.relift k) (VS.map S.Var.relift v) + ) data.side_infl; + data.side_infl <- side_infl'; + let side_dep' = HM.create (HM.length data.side_dep) in + HM.iter (fun k v -> + HM.replace side_dep' (S.Var.relift k) (VS.map S.Var.relift v) + ) data.side_dep; + data.side_dep <- side_dep'; data.st <- List.map (fun (k, v) -> S.Var.relift k, S.Dom.relift v) data.st; let var_messages' = HM.create (HM.length data.var_messages) in HM.iter (fun k v -> From 7876835e10c698440ae281c68d98b9eb6117a5ca Mon Sep 17 00:00:00 2001 From: Vesal Vojdani Date: Wed, 20 Oct 2021 13:51:24 +0300 Subject: [PATCH 080/402] Add side-restart (without local) example. --- tests/incremental/08-side-restart.c | 34 +++++++++++++++++++++++++ tests/incremental/08-side-restart.json | 18 +++++++++++++ tests/incremental/08-side-restart.patch | 2 ++ 3 files changed, 54 insertions(+) create mode 100644 tests/incremental/08-side-restart.c create mode 100644 tests/incremental/08-side-restart.json create mode 100644 tests/incremental/08-side-restart.patch diff --git a/tests/incremental/08-side-restart.c b/tests/incremental/08-side-restart.c new file mode 100644 index 0000000000..cdab5d408f --- /dev/null +++ b/tests/incremental/08-side-restart.c @@ -0,0 +1,34 @@ +#include +#include + +int g; + +void* t_fun1(void *arg) { + int x = g; + assert(x <= 8); + return NULL; +} + +void* t_fun2(void *arg) { + g = 0; + return NULL; +} + +int main() { + pthread_t id1, id2; + pthread_create(&id1, NULL, t_fun1, NULL); + + + int i = 0; + int j; + + for (j = 1; j < 10; j++) { + for (i = 0; i < j; i++) { + g = i; + } + } + assert(i <= 9); + + pthread_create(&id2, NULL, t_fun2, NULL); + return 0; +} \ No newline at end of file diff --git a/tests/incremental/08-side-restart.json b/tests/incremental/08-side-restart.json new file mode 100644 index 0000000000..88d0b04778 --- /dev/null +++ b/tests/incremental/08-side-restart.json @@ -0,0 +1,18 @@ +{ + "ana": { + "int": { + "interval": true + } + }, + "incremental": { + "reluctant": { + "on": false + }, + "restart": { + "wpoint": { + "enabled": false + } + } + + } +} \ No newline at end of file diff --git a/tests/incremental/08-side-restart.patch b/tests/incremental/08-side-restart.patch new file mode 100644 index 0000000000..32041b61ee --- /dev/null +++ b/tests/incremental/08-side-restart.patch @@ -0,0 +1,2 @@ +15d14 +< g = 0; From 2ef46cfe79895f5be365c28cce16ee5db06c7cc6 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 21 Oct 2021 11:36:36 +0300 Subject: [PATCH 081/402] Extract TD3 destabilize to ref to hackily make reluctant solve use restarting --- src/solvers/td3.ml | 42 ++++++++++++++++++++++++++---------------- 1 file changed, 26 insertions(+), 16 deletions(-) diff --git a/src/solvers/td3.ml b/src/solvers/td3.ml index 351ecf36f3..1564807c23 100644 --- a/src/solvers/td3.ml +++ b/src/solvers/td3.ml @@ -140,16 +140,11 @@ module WP = HM.replace infl y (VS.add x (try HM.find infl y with Not_found -> VS.empty)) in let add_sides y x = HM.replace sides y (VS.add x (try HM.find sides y with Not_found -> VS.empty)) in - let rec destabilize x = - if tracing then trace "sol2" "destabilize %a\n" S.Var.pretty_trace x; - let w = HM.find_default infl x VS.empty in - HM.replace infl x VS.empty; - VS.iter (fun y -> - HM.remove stable y; - HM.remove superstable y; - if not (HM.mem called y) then destabilize y - ) w - and destabilize_vs x = (* TODO remove? Only used for side_widen cycle. *) + + let destabilize_ref: (S.v -> unit) ref = ref (fun _ -> failwith "no destabilize yet") in + let destabilize x = !destabilize_ref x in (* must be eta-expanded to use changed destabilize_ref *) + + let rec destabilize_vs x = (* TODO remove? Only used for side_widen cycle. *) if tracing then trace "sol2" "destabilize_vs %a\n" S.Var.pretty_trace x; let w = HM.find_default infl x VS.empty in HM.replace infl x VS.empty; @@ -312,6 +307,17 @@ module WP = (* solve x Widen *) in + let rec destabilize_normal x = + if tracing then trace "sol2" "destabilize %a\n" S.Var.pretty_trace x; + let w = HM.find_default infl x VS.empty in + HM.replace infl x VS.empty; + VS.iter (fun y -> + HM.remove stable y; + HM.remove superstable y; + if not (HM.mem called y) then destabilize_normal y + ) w + in + start_event (); if GobConfig.get_bool "incremental.load" then ( @@ -366,12 +372,11 @@ module WP = ) w in - let destabilize_with_side = + destabilize_ref := if restart_sided then destabilize_with_side else - destabilize - in + destabilize_normal; (* If a global changes because of some assignment inside a function, we reanalyze, * but if it changes because of a different global initializer, then @@ -391,7 +396,7 @@ module WP = else ( ignore @@ Pretty.printf "Function %a has changed start state: %a\n" S.Var.pretty_trace v S.Dom.pretty_diff (d, d'); any_changed_start_state := true; - destabilize_with_side v + destabilize v ) | None -> any_changed_start_state := true; ignore @@ Pretty.printf "New start function %a not found in old list!\n" S.Var.pretty_trace v ) st; @@ -418,7 +423,7 @@ module WP = let old_infl = HM.find_default infl k VS.empty in Hashtbl.replace old_ret k (old_rho, old_infl))) rho; ) else ( - HM.iter (fun k _ -> if Set.mem (S.Var.var_id k) obsolete_entry then destabilize_with_side k) stable (* TODO: don't use string-based nodes *) + HM.iter (fun k _ -> if Set.mem (S.Var.var_id k) obsolete_entry then destabilize k) stable (* TODO: don't use string-based nodes *) ); (* We remove all unknowns for program points in changed or removed functions from rho, stable, infl and wpoint *) @@ -452,6 +457,8 @@ module WP = List.iter set_start st; + (* TODO: reluctant doesn't call destabilize on removed functions or old copies of modified functions (e.g. after removing write), so those globals don't get restarted *) + if not !any_changed_start_state && GobConfig.get_bool "incremental.reluctant.on" then ( (* solve on the return node of changed functions. Only destabilize the function's return node if the analysis result changed *) print_endline "Separately solving changed functions..."; @@ -462,7 +469,7 @@ module WP = solve x Widen; if not (op (HM.find rho x) old_rho) then ( HM.replace infl x old_infl; - destabilize_with_side x; + destabilize x; HM.replace stable x () ) ) old_ret; @@ -472,6 +479,9 @@ module WP = ) else ( List.iter set_start st; ); + + destabilize_ref := destabilize_normal; (* always use normal destabilize during actual solve *) + List.iter init vs; (* If we have multiple start variables vs, we might solve v1, then while solving v2 we side some global which v1 depends on with a new value. Then v1 is no longer stable and we have to solve it again. *) let i = ref 0 in From eb337af28a0032b1f596bad9b4f176b663cef369 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 21 Oct 2021 12:16:41 +0300 Subject: [PATCH 082/402] Add relifting to compare_runs --- src/framework/control.ml | 11 +++++++++-- src/solvers/postSolver.ml | 3 +++ 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/src/framework/control.ml b/src/framework/control.ml index 36b6f6422b..7ab712f3d0 100644 --- a/src/framework/control.ml +++ b/src/framework/control.ml @@ -413,10 +413,17 @@ struct if d1 = d2 then print_endline "Beware that you are comparing a run with itself! There should be no differences."; let r1, r2 = Tuple2.mapn (fun d -> let vh = Serialize.unmarshal (d ^ Filename.dir_sep ^ solver_file) in - (* TODO: no need to relift here? *) (* instead of rewriting Compare for EqConstrSys, just transform unmarshaled EqConstrSys solutions to GlobConstrSys soltuions *) let module Splitter = GlobConstrSolFromEqConstrSol (EQSys) (LHT) (GHT) in - Splitter.split_solution vh + let module S2 = Splitter.S2 in + let module VH = Splitter.VH in + + let vh' = VH.create (VH.length vh) in + VH.iter (fun k v -> + VH.replace vh' (S2.Var.relift k) (S2.Dom.relift v) + ) vh; + + Splitter.split_solution vh' ) (d1, d2) in Comp.compare (d1, d2) r1 r2; diff --git a/src/solvers/postSolver.ml b/src/solvers/postSolver.ml index 723da96d48..380bebcf21 100644 --- a/src/solvers/postSolver.ml +++ b/src/solvers/postSolver.ml @@ -58,6 +58,9 @@ module Prune: F = include Unit (S) (VH) let finalize ~vh ~reachable = + if get_bool "dbg.debug" then + print_endline "Pruning result"; + VH.filteri_inplace (fun x _ -> VH.mem reachable x ) vh From d5c1a42d08dcdf417cc3f0f7597d9322c28d840f Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 21 Oct 2021 12:23:44 +0300 Subject: [PATCH 083/402] Renumber duplicate test 00/28 --- .../{28-wpoint-restart-sound.c => 29-wpoint-restart-sound.c} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename tests/regression/00-sanity/{28-wpoint-restart-sound.c => 29-wpoint-restart-sound.c} (100%) diff --git a/tests/regression/00-sanity/28-wpoint-restart-sound.c b/tests/regression/00-sanity/29-wpoint-restart-sound.c similarity index 100% rename from tests/regression/00-sanity/28-wpoint-restart-sound.c rename to tests/regression/00-sanity/29-wpoint-restart-sound.c From 8bc2c89c94c2f22a7be95f8b959894b1ca3ca764 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 21 Oct 2021 12:55:59 +0300 Subject: [PATCH 084/402] Get pvals before executing any tf to maximize abort --- src/framework/constraints.ml | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/src/framework/constraints.ml b/src/framework/constraints.ml index d5a77ad91d..1dfc369c33 100644 --- a/src/framework/constraints.ml +++ b/src/framework/constraints.ml @@ -454,7 +454,7 @@ module FromSpec (S:Spec) (Cfg:CfgBackward) (I: Increment) and module GVar = Basetype.Variables and module D = S.D and module G = S.G - val tf : MyCFG.node * S.C.t -> (Cil.location * MyCFG.edge) list * MyCFG.node -> ((MyCFG.node * S.C.t) -> S.D.t) -> (MyCFG.node * S.C.t -> S.D.t -> unit) -> (Cil.varinfo -> G.t) -> (Cil.varinfo -> G.t -> unit) -> D.t + val tf : MyCFG.node * S.C.t -> (Cil.location * MyCFG.edge) list * MyCFG.node -> D.t -> ((MyCFG.node * S.C.t) -> S.D.t) -> (MyCFG.node * S.C.t -> S.D.t -> unit) -> (Cil.varinfo -> G.t) -> (Cil.varinfo -> G.t -> unit) -> D.t end = struct @@ -689,12 +689,12 @@ struct d ) - let tf (v,c) (edges, u) getl sidel getg sideg = - let pval = getl (u,c) in + let tf (v,c) (edges, u) pval getl sidel getg sideg = + (* let pval = getl (u,c) in *) let _, locs = List.fold_right (fun (f,e) (t,xs) -> f, (f,t)::xs) edges (Node.location v,[]) in List.fold_left2 (|>) pval (List.map (tf (v,Obj.repr (fun () -> c)) getl sidel getg sideg u) edges) locs - let tf (v,c) (e,u) getl sidel getg sideg = + let tf (v,c) (e,u) pval getl sidel getg sideg = let old_node = !current_node in let old_context = !M.current_context in current_node := Some u; @@ -703,7 +703,7 @@ struct current_node := old_node; M.current_context := old_context ) (fun () -> - let d = tf (v,c) (e,u) getl sidel getg sideg in + let d = tf (v,c) (e,u) pval getl sidel getg sideg in d ) @@ -713,12 +713,14 @@ struct None | _ -> let tf getl sidel getg sideg = - let tf' eu = tf (v,c) eu getl sidel getg sideg in + let get_pval (_, u) = getl (u, c) in + let tf' eu pval = tf (v,c) eu pval getl sidel getg sideg in match NodeH.find_option CfgTools.node_scc_global v with | Some scc when NodeH.mem scc.prev v -> let stricts = NodeH.find_all scc.prev v in - let xs_stricts = List.map tf' stricts in + let pvals_stricts = List.map get_pval stricts in (* get pvals before executing any tf to maximize abort *) + let xs_stricts = List.map2 tf' stricts pvals_stricts in if List.for_all S.D.is_bot xs_stricts then S.D.bot () else @@ -726,10 +728,13 @@ struct let equal = [%eq: (CilType.Location.t * Edge.t) list * Node.t] in let is_strict eu = List.exists (equal eu) stricts in let non_stricts = List.filter (neg is_strict) (Cfg.prev v) in - let xs_non_stricts = List.map tf' non_stricts in + let pvals_non_stricts = List.map get_pval non_stricts in (* get pvals before executing any tf to maximize abort *) + let xs_non_stricts = List.map2 tf' non_stricts pvals_non_stricts in List.fold_left S.D.join xs_strict xs_non_stricts | _ -> - let xs = List.map tf' (Cfg.prev v) in + let prevs = Cfg.prev v in + let pvals = List.map get_pval prevs in (* get pvals before executing any tf to maximize abort *) + let xs = List.map2 tf' prevs pvals in List.fold_left S.D.join (S.D.bot ()) xs in Some tf From a9103da3b7e0b6458f9afbcfe176df24fcf5c9fd Mon Sep 17 00:00:00 2001 From: Vesal Vojdani Date: Mon, 25 Oct 2021 11:48:18 +0300 Subject: [PATCH 085/402] [skip ci] Add context to patch. --- tests/incremental/08-side-restart.patch | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/tests/incremental/08-side-restart.patch b/tests/incremental/08-side-restart.patch index 32041b61ee..bc3607d94a 100644 --- a/tests/incremental/08-side-restart.patch +++ b/tests/incremental/08-side-restart.patch @@ -1,2 +1,10 @@ -15d14 -< g = 0; +--- a/tests/incremental/08-side-restart.c ++++ b/tests/incremental/08-side-restart.c +@@ -10,7 +10,6 @@ void* t_fun1(void *arg) { + } + + void* t_fun2(void *arg) { +- g = 0; + return NULL; + } + From 567ff0a0512280f743dc258bb5b6b6cc628ed327 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Mon, 25 Oct 2021 14:36:52 +0300 Subject: [PATCH 086/402] Fix Access.check_safe crash due to polymorphic Set Now accesses aren't iterated backwards anymore, but hopefully that doesn't matter. --- src/domains/access.ml | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/domains/access.ml b/src/domains/access.ml index d68463c5b4..b6614bfd59 100644 --- a/src/domains/access.ml +++ b/src/domains/access.ml @@ -436,12 +436,10 @@ let check_safe ls accs prev_safe = if ls = None then prev_safe else - (* TODO: Access uses polymorphic Set? *) - let accs = Set.of_list (AS.elements accs) in (* TODO: avoid converting between sets *) - let ord_enum = Set.backwards accs in (* hope that it is not nil *) - let lp_start = (fun (_,_,_,_,lp) -> lp) (BatOption.get (BatEnum.peek ord_enum)) in + let accs = AS.elements accs in (* hope that it is not nil *) + let lp_start = (fun (_,_,_,_,lp) -> lp) (List.hd accs) in (* ignore(printf "starting with lockset %a\n" LSSet.pretty lp_start); *) - match BatEnum.fold check_accs (None, lp_start, false) (Set.backwards accs), prev_safe with + match List.fold_left check_accs (None, lp_start, false) accs, prev_safe with | (None, _,_), _ -> (* ignore(printf "this batch is safe\n"); *) prev_safe From ed7045f9cd7c997ea5d8800302a6592872d63505 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Mon, 25 Oct 2021 15:21:57 +0300 Subject: [PATCH 087/402] Fix incorrect pretty_diff usage in compare_runs --- src/framework/constraints.ml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/framework/constraints.ml b/src/framework/constraints.ml index 70bfbb9655..9887d9898f 100644 --- a/src/framework/constraints.ml +++ b/src/framework/constraints.ml @@ -1062,7 +1062,7 @@ struct f_eq () else if b1 then begin if get_bool "solverdiffs" then - ignore (Pretty.printf "Global %a is more precise using left:\n%a\n" Sys.GVar.pretty_trace k G.pretty_diff (v1,v2)); + ignore (Pretty.printf "Global %a is more precise using left:\n%a\n" Sys.GVar.pretty_trace k G.pretty_diff (v2,v1)); f_le () end else if b2 then begin if get_bool "solverdiffs" then @@ -1085,7 +1085,7 @@ struct incr eq else if b1 then begin if get_bool "solverdiffs" then - ignore (Pretty.printf "%a @@ %a is more precise using left:\n%a\n" Node.pretty_plain k CilType.Location.pretty (Node.location k) D.pretty_diff (v1,v2)); + ignore (Pretty.printf "%a @@ %a is more precise using left:\n%a\n" Node.pretty_plain k CilType.Location.pretty (Node.location k) D.pretty_diff (v2,v1)); incr le end else if b2 then begin if get_bool "solverdiffs" then @@ -1117,7 +1117,7 @@ struct f_eq () else if b1 then begin (* if get_bool "solverdiffs" then *) - (* ignore (Pretty.printf "%a @@ %a is more precise using left:\n%a\n" pretty_node k CilType.Location.pretty (getLoc k) D.pretty_diff (v1,v2)); *) + (* ignore (Pretty.printf "%a @@ %a is more precise using left:\n%a\n" pretty_node k CilType.Location.pretty (getLoc k) D.pretty_diff (v2,v1)); *) f_le () end else if b2 then begin (* if get_bool "solverdiffs" then *) From 8bcd839f69db94446ae43b29f5a7b518f7cbcec9 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Mon, 25 Oct 2021 15:38:49 +0300 Subject: [PATCH 088/402] Add pretty_diff for incomparable compare_runs --- src/framework/constraints.ml | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/framework/constraints.ml b/src/framework/constraints.ml index 9887d9898f..14eef7ea5d 100644 --- a/src/framework/constraints.ml +++ b/src/framework/constraints.ml @@ -1068,8 +1068,13 @@ struct if get_bool "solverdiffs" then ignore (Pretty.printf "Global %a is more precise using right:\n%a\n" Sys.GVar.pretty_trace k G.pretty_diff (v1,v2)); f_gr () - end else + end else begin + if get_bool "solverdiffs" then ( + ignore (Pretty.printf "Global %a is incomparable (diff):\n%a\n" Sys.GVar.pretty_trace k G.pretty_diff (v1,v2)); + ignore (Pretty.printf "Global %a is incomparable (reverse diff):\n%a\n" Sys.GVar.pretty_trace k G.pretty_diff (v2,v1)); + ); f_uk () + end in GH.iter f g1; Printf.printf "globals:\tequal = %d\tleft = %d\tright = %d\tincomparable = %d\n" !eq !le !gr !uk @@ -1091,8 +1096,13 @@ struct if get_bool "solverdiffs" then ignore (Pretty.printf "%a @@ %a is more precise using right:\n%a\n" Node.pretty_plain k CilType.Location.pretty (Node.location k) D.pretty_diff (v1,v2)); incr gr - end else + end else begin + if get_bool "solverdiffs" then ( + ignore (Pretty.printf "%a @@ %a is incomparable (diff):\n%a\n" Node.pretty_plain k CilType.Location.pretty (Node.location k) D.pretty_diff (v1,v2)); + ignore (Pretty.printf "%a @@ %a is incomparable (reverse diff):\n%a\n" Node.pretty_plain k CilType.Location.pretty (Node.location k) D.pretty_diff (v2,v1)); + ); incr uk + end in PP.iter f h1; (* let k1 = Set.of_enum @@ PP.keys h1 in From 4af635ea70f94d260eb01b14012aff6e931b10e8 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Mon, 25 Oct 2021 16:59:42 +0300 Subject: [PATCH 089/402] Add solverdiffs output to compare_locals_ctx compare_runs --- src/framework/constraints.ml | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/framework/constraints.ml b/src/framework/constraints.ml index 14eef7ea5d..464fc10541 100644 --- a/src/framework/constraints.ml +++ b/src/framework/constraints.ml @@ -1126,15 +1126,20 @@ struct if b1 && b2 then f_eq () else if b1 then begin - (* if get_bool "solverdiffs" then *) - (* ignore (Pretty.printf "%a @@ %a is more precise using left:\n%a\n" pretty_node k CilType.Location.pretty (getLoc k) D.pretty_diff (v2,v1)); *) + if get_bool "solverdiffs" then + ignore (Pretty.printf "%a is more precise using left:\n%a\n" Sys.LVar.pretty_trace k D.pretty_diff (v2,v1)); f_le () end else if b2 then begin - (* if get_bool "solverdiffs" then *) - (* ignore (Pretty.printf "%a @@ %a is more precise using right:\n%a\n" pretty_node k CilType.Location.pretty (getLoc k) D.pretty_diff (v1,v2)); *) + if get_bool "solverdiffs" then + ignore (Pretty.printf "%a is more precise using right:\n%a\n" Sys.LVar.pretty_trace k D.pretty_diff (v1,v2)); f_gr () - end else + end else begin + if get_bool "solverdiffs" then ( + ignore (Pretty.printf "%a is incomparable (diff):\n%a\n" Sys.LVar.pretty_trace k D.pretty_diff (v1,v2)); + ignore (Pretty.printf "%a is incomparable (reverse diff):\n%a\n" Sys.LVar.pretty_trace k D.pretty_diff (v2,v1)); + ); f_uk () + end in LH.iter f h1; (* let k1 = Set.of_enum @@ PP.keys h1 in *) From 7535efab82e2461599593a5ea14f596f9aa5e3d1 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Mon, 25 Oct 2021 17:00:00 +0300 Subject: [PATCH 090/402] Add symmetric no_ctx_in_left counter to compare_runs --- src/framework/constraints.ml | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/framework/constraints.ml b/src/framework/constraints.ml index 464fc10541..f8b254a508 100644 --- a/src/framework/constraints.ml +++ b/src/framework/constraints.ml @@ -1113,7 +1113,7 @@ struct Printf.printf "locals: \tequal = %d\tleft = %d\tright = %d\tincomparable = %d\n" !eq !le !gr !uk let compare_locals_ctx h1 h2 = - let eq, le, gr, uk, no2 = ref 0, ref 0, ref 0, ref 0, ref 0 in + let eq, le, gr, uk, no2, no1 = ref 0, ref 0, ref 0, ref 0, ref 0, ref 0 in let f_eq () = incr eq in let f_le () = incr le in let f_gr () = incr gr in @@ -1142,11 +1142,15 @@ struct end in LH.iter f h1; + let f k v2 = + if not (LH.mem h1 k) then incr no1 + in + LH.iter f h2; (* let k1 = Set.of_enum @@ PP.keys h1 in *) (* let k2 = Set.of_enum @@ PP.keys h2 in *) (* let o1 = Set.cardinal @@ Set.diff k1 k2 in *) (* let o2 = Set.cardinal @@ Set.diff k2 k1 in *) - Printf.printf "locals_ctx:\tequal = %d\tleft = %d\tright = %d\tincomparable = %d\tno_ctx_in_right = %d\n" !eq !le !gr !uk !no2 + Printf.printf "locals_ctx:\tequal = %d\tleft = %d\tright = %d\tincomparable = %d\tno_ctx_in_right = %d\tno_ctx_in_left = %d\n" !eq !le !gr !uk !no2 !no1 let compare (name1,name2) (l1,g1) (l2,g2) = let one_ctx (n,_) v h = From 68c282ad7accf9a2dd0e2dac1ae9372f7f06758a Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Tue, 26 Oct 2021 16:24:02 +0300 Subject: [PATCH 091/402] Add interactive stable pruning to TD3 This avoids incremental postsolving keeping old unreachable things superstable. --- src/solvers/td3.ml | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/solvers/td3.ml b/src/solvers/td3.ml index 8d71ab601b..5ebad1e773 100644 --- a/src/solvers/td3.ml +++ b/src/solvers/td3.ml @@ -545,6 +545,20 @@ module WP = print_newline (); ); + (* Prune other data structures than rho with reachable. + These matter for the incremental data. *) + let module IncrPrune: PostSolver.S with module S = S and module VH = HM = + struct + include PostSolver.Unit (S) (HM) + + let finalize ~vh ~reachable = + VH.filteri_inplace (fun x _ -> + VH.mem reachable x + ) stable + (* TODO: prune other data structures? *) + end + in + (* postsolver also populates side_dep and side_infl *) let module SideInfl: PostSolver.S with module S = S and module VH = HM = struct @@ -592,7 +606,7 @@ module WP = end include PostSolver.ListArgFromStdArg (S) (HM) (Arg) - let postsolvers = (module SideInfl: M) :: (module IncrWarn: M) :: postsolvers + let postsolvers = (module IncrPrune: M) :: (module SideInfl: M) :: (module IncrWarn: M) :: postsolvers let init_reachable ~vh = if incr_verify then From 422169c55211eef5d24e7326274c076fab1e205e Mon Sep 17 00:00:00 2001 From: Vesal Vojdani Date: Sat, 6 Nov 2021 10:03:10 +0000 Subject: [PATCH 092/402] [skip ci] Init state tests; eq on master, but not when merged into this branch. --- tests/incremental/00-justglob.c | 2 ++ tests/incremental/00-justglob.json | 3 +++ tests/incremental/00-justglob.patch | 8 ++++++++ 3 files changed, 13 insertions(+) create mode 100644 tests/incremental/00-justglob.c create mode 100644 tests/incremental/00-justglob.json create mode 100644 tests/incremental/00-justglob.patch diff --git a/tests/incremental/00-justglob.c b/tests/incremental/00-justglob.c new file mode 100644 index 0000000000..61b059f8ea --- /dev/null +++ b/tests/incremental/00-justglob.c @@ -0,0 +1,2 @@ +int max_domains = 0; +int main() {} diff --git a/tests/incremental/00-justglob.json b/tests/incremental/00-justglob.json new file mode 100644 index 0000000000..0e0dcd235c --- /dev/null +++ b/tests/incremental/00-justglob.json @@ -0,0 +1,3 @@ +{ + +} \ No newline at end of file diff --git a/tests/incremental/00-justglob.patch b/tests/incremental/00-justglob.patch new file mode 100644 index 0000000000..ff588a543f --- /dev/null +++ b/tests/incremental/00-justglob.patch @@ -0,0 +1,8 @@ +diff --git a/tests/incremental/00-justglob.c b/tests/incremental/00-justglob.c +index 55c1e2271..ec1c6d041 100644 +--- a/tests/incremental/00-justglob.c ++++ b/tests/incremental/00-justglob.c +@@ -1,2 +1,2 @@ +-int max_domains = 0; ++int max_domains = 4; + int main() {} From d67168743aeedc4add69fd23aa6c9f4f8b7cef52 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Mon, 8 Nov 2021 11:48:21 +0200 Subject: [PATCH 093/402] Fix some restarting with reluctant destabilization --- src/solvers/td3.ml | 34 +++++++++++++++++++++++----------- 1 file changed, 23 insertions(+), 11 deletions(-) diff --git a/src/solvers/td3.ml b/src/solvers/td3.ml index c9c54920e8..62a73545d3 100644 --- a/src/solvers/td3.ml +++ b/src/solvers/td3.ml @@ -397,6 +397,7 @@ module WP = List.iter (fun a -> print_endline ("Completely changed function: " ^ a.svar.vname)) changed_funs; List.iter (fun (f,_,_) -> print_endline ("Partially changed function: " ^ (f.svar.vname))) part_changed_funs; + List.iter (fun f -> print_endline ("Removed function: " ^ (f.svar.vname))) removed_funs; let old_ret = Hashtbl.create 103 in if GobConfig.get_bool "incremental.reluctant.on" then ( @@ -437,20 +438,27 @@ module WP = delete_marked rho; delete_marked infl; delete_marked wpoint; - delete_marked stable; - delete_marked side_dep; - delete_marked side_infl; - - - print_data data "Data after clean-up"; - (* reachability will populate these tables for incremental global restarting *) - HM.clear side_dep; - HM.clear side_infl; + (* destabilize_with_side doesn't have all infl to follow anymore, so should somewhat work with reluctant *) + if restart_sided then ( + (* restarts old copies of functions and their (removed) side effects *) + print_endline "Destabilizing sides of changed functions, primary old nodes and removed functions ..."; + let stable_copy = HM.copy stable in (* use copy because destabilize modifies stable *) + HM.iter (fun k _ -> if Hashtbl.mem marked_for_deletion (S.Var.var_id k) then (ignore (Pretty.printf "marked %a\n" S.Var.pretty_trace k); destabilize k)) stable_copy; (* TODO: don't use string-based nodes *) + ); (* Call side on all globals and functions in the start variables to make sure that changes in the initializers are propagated. * This also destabilizes start functions if their start state changes because of globals that are neither in the start variables nor in the contexts *) - List.iter (fun (v,d) -> side v d) st; + List.iter (fun (v,d) -> + if restart_sided then + destabilize v; (* restart side effect from start *) + side v d + ) st; + + delete_marked stable; + delete_marked side_dep; + delete_marked side_infl; + print_data data "Data after clean-up"; (* TODO: reluctant doesn't call destabilize on removed functions or old copies of modified functions (e.g. after removing write), so those globals don't get restarted *) @@ -471,7 +479,11 @@ module WP = ) old_ret; print_endline "Final solve..." - ) + ); + + (* reachability will populate these tables for incremental global restarting *) + HM.clear side_dep; + HM.clear side_infl; ) else ( List.iter set_start st; ); From ec0da7e267784bac42215d35da1b579da2b0cbbf Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Mon, 8 Nov 2021 11:48:35 +0200 Subject: [PATCH 094/402] Change incremental.reluctant.compare default to equal --- src/util/defaults.ml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/util/defaults.ml b/src/util/defaults.ml index 75dea12582..4e932288e5 100644 --- a/src/util/defaults.ml +++ b/src/util/defaults.ml @@ -155,7 +155,7 @@ let _ = () ; reg Incremental "incremental.stable" "true" "Reuse the stable set and selectively destabilize it (recommended)." ; reg Incremental "incremental.wpoint" "false" "Reuse the wpoint set (not recommended). Reusing the wpoint will combine existing results at previous widening points." ; reg Incremental "incremental.reluctant.on" "true" "Destabilize nodes in changed functions reluctantly" - ; reg Incremental "incremental.reluctant.compare" "'leq'" "In order to reuse the function's old abstract value the new abstract value must be leq (focus on efficiency) or equal (focus on precision) compared to the old." + ; reg Incremental "incremental.reluctant.compare" "'equal'" "In order to reuse the function's old abstract value the new abstract value must be leq (focus on efficiency) or equal (focus on precision) compared to the old." ; reg Incremental "incremental.compare" "'ast'" "Which comparison should be used for functions? 'ast'/'cfg' (cfg comparison also differentiates which nodes of a function have changed)" ; reg Incremental "incremental.restart.sided.enabled" "true" "TODO" ; reg Incremental "incremental.restart.sided.only-global" "false" "TODO" From 1589c8553c614182e8faf5624471a43955d15f27 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Mon, 8 Nov 2021 11:48:53 +0200 Subject: [PATCH 095/402] Disable incremental.reluctant.on by default --- src/util/defaults.ml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/util/defaults.ml b/src/util/defaults.ml index 4e932288e5..6eef5e0d04 100644 --- a/src/util/defaults.ml +++ b/src/util/defaults.ml @@ -154,7 +154,7 @@ let _ = () ; reg Incremental "incremental.save" "false" "Store incremental analysis results." ; reg Incremental "incremental.stable" "true" "Reuse the stable set and selectively destabilize it (recommended)." ; reg Incremental "incremental.wpoint" "false" "Reuse the wpoint set (not recommended). Reusing the wpoint will combine existing results at previous widening points." - ; reg Incremental "incremental.reluctant.on" "true" "Destabilize nodes in changed functions reluctantly" + ; reg Incremental "incremental.reluctant.on" "false" "Destabilize nodes in changed functions reluctantly" ; reg Incremental "incremental.reluctant.compare" "'equal'" "In order to reuse the function's old abstract value the new abstract value must be leq (focus on efficiency) or equal (focus on precision) compared to the old." ; reg Incremental "incremental.compare" "'ast'" "Which comparison should be used for functions? 'ast'/'cfg' (cfg comparison also differentiates which nodes of a function have changed)" ; reg Incremental "incremental.restart.sided.enabled" "true" "TODO" From a7913d639013a1c1897bbad0e7aaed79161a03b5 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Mon, 8 Nov 2021 13:52:08 +0200 Subject: [PATCH 096/402] Fix TD3 restart wpoint with abort --- src/solvers/td3.ml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/solvers/td3.ml b/src/solvers/td3.ml index 1d741471b2..2247421f77 100644 --- a/src/solvers/td3.ml +++ b/src/solvers/td3.ml @@ -370,7 +370,7 @@ module WP = if not (restart_once && HM.mem restarted_wpoint y) then ( if tracing then trace "sol2" "wpoint restart %a ## %a\n" S.Var.pretty_trace y S.Dom.pretty (HM.find_default rho y (S.Dom.bot ())); HM.replace rho y (S.Dom.bot ()); - (* destabilize y *) (* TODO: would this do anything on called? *) + destabilize y; (* required for abort (front) *) if restart_once then (* avoid populating hashtable unnecessarily *) HM.replace restarted_wpoint y (); ) From df080d9b1e3bc111f3c3663a7e90e1ec621884ff Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Mon, 8 Nov 2021 13:54:58 +0200 Subject: [PATCH 097/402] Disable incremental.restart.wpoint.enabled by default --- src/util/defaults.ml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/util/defaults.ml b/src/util/defaults.ml index d8c00fa815..15978c121c 100644 --- a/src/util/defaults.ml +++ b/src/util/defaults.ml @@ -159,7 +159,7 @@ let _ = () ; reg Incremental "incremental.compare" "'ast'" "Which comparison should be used for functions? 'ast'/'cfg' (cfg comparison also differentiates which nodes of a function have changed)" ; reg Incremental "incremental.restart.sided.enabled" "true" "TODO" ; reg Incremental "incremental.restart.sided.only-global" "false" "TODO" - ; reg Incremental "incremental.restart.wpoint.enabled" "true" "TODO" + ; reg Incremental "incremental.restart.wpoint.enabled" "false" "TODO" ; reg Incremental "incremental.restart.wpoint.once" "true" "TODO" ; reg Incremental "incremental.verify" "true" "TODO" From 1aea84c7b2d32bdc3f5462355c4f40012aa060cb Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Mon, 8 Nov 2021 13:57:11 +0200 Subject: [PATCH 098/402] Disable TD3 abort by default --- src/util/defaults.ml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/util/defaults.ml b/src/util/defaults.ml index 15978c121c..27a0686b24 100644 --- a/src/util/defaults.ml +++ b/src/util/defaults.ml @@ -209,8 +209,8 @@ let _ = () ; reg Experimental "exp.solver.td3.space" "false" "Should the td3 solver only keep values at widening points?" ; reg Experimental "exp.solver.td3.space_cache" "true" "Should the td3-space solver cache values?" ; reg Experimental "exp.solver.td3.space_restore" "true" "Should the td3-space solver restore values for non-widening-points? Not needed for generating warnings, but needed for inspecting output!" - ; reg Experimental "exp.solver.td3.abort" "true" "TODO" - ; reg Experimental "exp.solver.td3.abort-verify" "true" "TODO" + ; reg Experimental "exp.solver.td3.abort" "false" "TODO" + ; reg Experimental "exp.solver.td3.abort-verify" "false" "TODO" ; reg Experimental "exp.solver.slr4.restart_count" "1" "How many times SLR4 is allowed to switch from restarting iteration to increasing iteration." ; reg Experimental "exp.fast_global_inits" "true" "Only generate one 'a[MyCFG.all_array_index_exp] = x' for all assignments a[...] = x for a global array a[n]." ; reg Experimental "exp.uninit-ptr-safe" "false" "Assume that uninitialized stack-allocated pointers may only point to variables not in the program or null." From fae2e6f4f666f4412ac0349ef38979d3fe46f7f7 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Mon, 8 Nov 2021 16:23:21 +0200 Subject: [PATCH 099/402] Fix duplicate test number for apron/td3-self-abort-complex --- .../{71-td3-self-abort-complex.c => 73-td3-self-abort-complex.c} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename tests/regression/36-apron/{71-td3-self-abort-complex.c => 73-td3-self-abort-complex.c} (100%) diff --git a/tests/regression/36-apron/71-td3-self-abort-complex.c b/tests/regression/36-apron/73-td3-self-abort-complex.c similarity index 100% rename from tests/regression/36-apron/71-td3-self-abort-complex.c rename to tests/regression/36-apron/73-td3-self-abort-complex.c From b1e6d35c5033dde7960d99cf54877aaca1097e0d Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Mon, 8 Nov 2021 17:16:03 +0200 Subject: [PATCH 100/402] Install sha256sum in macos workflow --- .github/workflows/locked.yml | 4 ++++ .github/workflows/unlocked.yml | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/.github/workflows/locked.yml b/.github/workflows/locked.yml index d484075105..5b27607eba 100644 --- a/.github/workflows/locked.yml +++ b/.github/workflows/locked.yml @@ -34,6 +34,10 @@ jobs: - name: Install dependencies run: opam install . --deps-only --locked + - name: Install sha256sum (macOS) # https://github.com/actions/virtual-environments/issues/90#issuecomment-553279378 + if: ${{ matrix.os == 'macos-latest' }} + run: brew install coreutils + - name: Build run: ./make.sh nat diff --git a/.github/workflows/unlocked.yml b/.github/workflows/unlocked.yml index 3bddd4a454..648077f6a1 100644 --- a/.github/workflows/unlocked.yml +++ b/.github/workflows/unlocked.yml @@ -49,6 +49,10 @@ jobs: opam depext apron opam install apron + - name: Install sha256sum (macOS) # https://github.com/actions/virtual-environments/issues/90#issuecomment-553279378 + if: ${{ matrix.os == 'macos-latest' }} + run: brew install coreutils + - name: Build run: ./make.sh nat From f19521f59df4fbf3534c8bda4825b49a423e9714 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Mon, 8 Nov 2021 17:23:11 +0200 Subject: [PATCH 101/402] Disable broken SV-COMP marshaling --- .../29-svcomp/27-td3-front-via-destab-infl.c | 2 +- tests/regression/29-svcomp/28-svcomp-marshal.c | 11 +++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) create mode 100644 tests/regression/29-svcomp/28-svcomp-marshal.c diff --git a/tests/regression/29-svcomp/27-td3-front-via-destab-infl.c b/tests/regression/29-svcomp/27-td3-front-via-destab-infl.c index d39cb15046..a0e5b8a00e 100644 --- a/tests/regression/29-svcomp/27-td3-front-via-destab-infl.c +++ b/tests/regression/29-svcomp/27-td3-front-via-destab-infl.c @@ -1,4 +1,4 @@ -// PARAM: --set ana.activated[+] var_eq --set ana.activated[+] symb_locks --set ana.activated[+] region --enable ana.sv-comp.enabled --set ana.specification "CHECK( init(main()), LTL(G ! call(reach_error())) )" +// NOMARSHAL PARAM: --set ana.activated[+] var_eq --set ana.activated[+] symb_locks --set ana.activated[+] region --enable ana.sv-comp.enabled --set ana.specification "CHECK( init(main()), LTL(G ! call(reach_error())) )" // creduced from ldv-linux-4.2-rc1/linux-4.2-rc1.tar.xz-43_2a-drivers--scsi--qla4xxx--qla4xxx.ko-entry_point.cil.out.i // this program and params are really minimal, which produced a TD3 abort verify error, so don't simplify diff --git a/tests/regression/29-svcomp/28-svcomp-marshal.c b/tests/regression/29-svcomp/28-svcomp-marshal.c new file mode 100644 index 0000000000..b61335f029 --- /dev/null +++ b/tests/regression/29-svcomp/28-svcomp-marshal.c @@ -0,0 +1,11 @@ +// SKIP PARAM: --enable ana.sv-comp.enabled --set ana.specification "CHECK( init(main()), LTL(G ! call(reach_error())) )" +// SV-COMP marshaling doesn't work + +void f() { + +} + +int main() { + f(); + return 0; +} From 2abcf136b51489096ea00b605e820668bd005945 Mon Sep 17 00:00:00 2001 From: Vesal Vojdani Date: Tue, 9 Nov 2021 20:27:40 +0200 Subject: [PATCH 102/402] Indent file; maybe delete it? --- .../34-localization/05-nested.w.counter.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/tests/regression/34-localization/05-nested.w.counter.c b/tests/regression/34-localization/05-nested.w.counter.c index 1f2118f072..2d0cca1853 100644 --- a/tests/regression/34-localization/05-nested.w.counter.c +++ b/tests/regression/34-localization/05-nested.w.counter.c @@ -1,12 +1,11 @@ // Variant of nested.c with a counter. void main() { - int z = 0; - for (int i=0; i<10 ; i++) - { - z = z+1; - for (int j = 0; j < 10 ; j++) ; - z = z+1; - } - return ; + int z = 0; + for (int i=0; i<10 ; i++) { + z = z+1; + for (int j = 0; j < 10 ; j++) ; + z = z+1; // was this intended to be inner loop? + } + return ; } From ba983d8e425185b9cf2b625401bb185bca2c6a31 Mon Sep 17 00:00:00 2001 From: Vesal Vojdani Date: Tue, 9 Nov 2021 20:37:04 +0200 Subject: [PATCH 103/402] Switching localized widen tests to td3; restart works :) --- tests/regression/34-localization/01-nested.c | 5 +++-- tests/regression/34-localization/02-hybrid.c | 7 ++++--- tests/regression/34-localization/03-nested2.c | 8 ++++---- tests/regression/34-localization/04-hh.c | 7 ++++--- 4 files changed, 15 insertions(+), 12 deletions(-) diff --git a/tests/regression/34-localization/01-nested.c b/tests/regression/34-localization/01-nested.c index 775dfeb5c7..9e693f9eb2 100644 --- a/tests/regression/34-localization/01-nested.c +++ b/tests/regression/34-localization/01-nested.c @@ -1,5 +1,6 @@ -// PARAM: --enable ana.int.interval --set solver slr3 -// Example from Amato-Scozzari, SAS 2013 +// PARAM: --enable ana.int.interval --set solver td3 +// ALSO: --enable ana.int.interval --set solver slr3 +// Example from Halbwachs-Henry, SAS 2012 // Localized widening should be able to prove that i=10 at the end // of the nested loops. diff --git a/tests/regression/34-localization/02-hybrid.c b/tests/regression/34-localization/02-hybrid.c index 231b298d33..45e746afad 100644 --- a/tests/regression/34-localization/02-hybrid.c +++ b/tests/regression/34-localization/02-hybrid.c @@ -1,5 +1,6 @@ -// PARAM: --enable ana.int.interval --set solver slr4 -// Example from Amato-Scozzari, SAS 2013 +// PARAM: --enable ana.int.interval --set solver td3 --enable incremental.restart.wpoint.enabled --disable incremental.restart.wpoint.once --set sem.int.signed_overflow assume_none +// ALSO: --enable ana.int.interval --set solver sl4 --set sem.int.signed_overflow assume_none +// Example from Amato-Scozzari, SAS 2013, based on Halbwachs-Henry, SAS 2012. // Localized narrowing with restart policy should be able to prove that // 0 <= i <= 10 inside the inner loop. @@ -9,7 +10,7 @@ void main() while (1) { i++; for (int j=0; j < 10; j++) { - assert(0 >= i); // UNKNOWN + assert(0 <= i); assert(i <= 10); } if (i>9) i=0; diff --git a/tests/regression/34-localization/03-nested2.c b/tests/regression/34-localization/03-nested2.c index 19d75a5ab2..a248172c7c 100644 --- a/tests/regression/34-localization/03-nested2.c +++ b/tests/regression/34-localization/03-nested2.c @@ -1,7 +1,7 @@ -// PARAM: --enable ana.int.interval --set solver slr4 +// PARAM: --enable ana.int.interval --set solver td3 --set sem.int.signed_overflow assume_none +// ALSO: --enable ana.int.interval --set solver slr3 --set sem.int.signed_overflow assume_none // Example from Amato-Scozzari, SAS 2013 -// Localized narrowing should be able to prove that i >= 0 in the outer -// loop. +// Localized narrowing should be able to prove that i >= 0 in the outer loop. void main() { @@ -10,7 +10,7 @@ void main() int j = 0; for (; j<10; j++) ; i=i+11-j; - assert(i >= 0); // UNKNOWN + assert(i >= 0); } return; } diff --git a/tests/regression/34-localization/04-hh.c b/tests/regression/34-localization/04-hh.c index 85dcc0a509..f5fe672d2a 100644 --- a/tests/regression/34-localization/04-hh.c +++ b/tests/regression/34-localization/04-hh.c @@ -1,5 +1,6 @@ -// PARAM: --enable ana.int.interval --set solver slr4 -// Example from Amato-Scozzari, SAS 2013 +// PARAM: --enable ana.int.interval --set solver td3 --enable exp.partition-arrays.enabled --set ana.activated "['base','threadid','threadflag','expRelation','mallocWrapper','apron']" --set exp.privatization none --set exp.apron.privatization dummy --set sem.int.signed_overflow assume_none +// ALSO: --enable ana.int.interval --set solver slr3 --enable exp.partition-arrays.enabled --set ana.activated "['base','threadid','threadflag','expRelation','mallocWrapper','apron']" --set exp.privatization none --set exp.apron.privatization dummy --set sem.int.signed_overflow assume_none +// Example from Halbwachs-Henry, SAS 2012 // Localized widening or restart policy should be able to prove that i <= j+3 // if the abstract domain is powerful enough. @@ -13,7 +14,7 @@ void main() j=j+1; } i = i-j+1; - assert(i <= j+3); // UNKNOWN + assert(i <= j+3); } return ; } From aea8d2fbe29cb8f49d4665f4a1a5b076e54271ae Mon Sep 17 00:00:00 2001 From: Vesal Vojdani Date: Tue, 9 Nov 2021 20:38:53 +0200 Subject: [PATCH 104/402] Add test needing local restart for fun calls. --- tests/incremental/48-local-wpoint-funcall.c | 18 ++++++++++++++++++ tests/incremental/48-local-wpoint-funcall.json | 14 ++++++++++++++ .../incremental/48-local-wpoint-funcall.patch | 13 +++++++++++++ 3 files changed, 45 insertions(+) create mode 100644 tests/incremental/48-local-wpoint-funcall.c create mode 100644 tests/incremental/48-local-wpoint-funcall.json create mode 100644 tests/incremental/48-local-wpoint-funcall.patch diff --git a/tests/incremental/48-local-wpoint-funcall.c b/tests/incremental/48-local-wpoint-funcall.c new file mode 100644 index 0000000000..123a86004e --- /dev/null +++ b/tests/incremental/48-local-wpoint-funcall.c @@ -0,0 +1,18 @@ +#include + +int f(int x) { + return 1; +} + +int main() { + int x = 0; + int y; + while (x < 10) { + y = f(x); + x = x + y; + assert(x == 0); + } + + assert(0); + return 0; +} \ No newline at end of file diff --git a/tests/incremental/48-local-wpoint-funcall.json b/tests/incremental/48-local-wpoint-funcall.json new file mode 100644 index 0000000000..01e6f27a23 --- /dev/null +++ b/tests/incremental/48-local-wpoint-funcall.json @@ -0,0 +1,14 @@ +{ + "ana": { + "int": { + "interval": true + } + }, + "incremental": { + "restart": { + "wpoint": { + "enabled": false + } + } + } +} \ No newline at end of file diff --git a/tests/incremental/48-local-wpoint-funcall.patch b/tests/incremental/48-local-wpoint-funcall.patch new file mode 100644 index 0000000000..87b48792c0 --- /dev/null +++ b/tests/incremental/48-local-wpoint-funcall.patch @@ -0,0 +1,13 @@ +diff --git a/tests/incremental/48-local-wpoint-funcall.c b/tests/incremental/48-local-wpoint-funcall.c +index 1de02a51b..bdcb2875f 100644 +--- a/tests/incremental/48-local-wpoint-funcall.c ++++ b/tests/incremental/48-local-wpoint-funcall.c +@@ -1,7 +1,7 @@ + #include + + int f(int x) { +- return 1; ++ return 0; + } + + int main() { From 014977669812d8fe0de216989e7505a8064e8053 Mon Sep 17 00:00:00 2001 From: Vesal Vojdani Date: Tue, 9 Nov 2021 20:52:37 +0200 Subject: [PATCH 105/402] Skip apron test, but still better to keep here. --- tests/regression/34-localization/04-hh.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/regression/34-localization/04-hh.c b/tests/regression/34-localization/04-hh.c index f5fe672d2a..29ef3dc6c7 100644 --- a/tests/regression/34-localization/04-hh.c +++ b/tests/regression/34-localization/04-hh.c @@ -1,4 +1,4 @@ -// PARAM: --enable ana.int.interval --set solver td3 --enable exp.partition-arrays.enabled --set ana.activated "['base','threadid','threadflag','expRelation','mallocWrapper','apron']" --set exp.privatization none --set exp.apron.privatization dummy --set sem.int.signed_overflow assume_none +// SKIP PARAM: --enable ana.int.interval --set solver td3 --enable exp.partition-arrays.enabled --set ana.activated "['base','threadid','threadflag','expRelation','mallocWrapper','apron']" --set exp.privatization none --set exp.apron.privatization dummy --set sem.int.signed_overflow assume_none // ALSO: --enable ana.int.interval --set solver slr3 --enable exp.partition-arrays.enabled --set ana.activated "['base','threadid','threadflag','expRelation','mallocWrapper','apron']" --set exp.privatization none --set exp.apron.privatization dummy --set sem.int.signed_overflow assume_none // Example from Halbwachs-Henry, SAS 2012 // Localized widening or restart policy should be able to prove that i <= j+3 From 41b19eeb553eec920b099476826129f3d1c7b2c6 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 10 Nov 2021 12:33:35 +0200 Subject: [PATCH 106/402] Revert "Install sha256sum in macos workflow" This reverts commit b1e6d35c5033dde7960d99cf54877aaca1097e0d. --- .github/workflows/locked.yml | 4 ---- .github/workflows/unlocked.yml | 4 ---- 2 files changed, 8 deletions(-) diff --git a/.github/workflows/locked.yml b/.github/workflows/locked.yml index 5b27607eba..d484075105 100644 --- a/.github/workflows/locked.yml +++ b/.github/workflows/locked.yml @@ -34,10 +34,6 @@ jobs: - name: Install dependencies run: opam install . --deps-only --locked - - name: Install sha256sum (macOS) # https://github.com/actions/virtual-environments/issues/90#issuecomment-553279378 - if: ${{ matrix.os == 'macos-latest' }} - run: brew install coreutils - - name: Build run: ./make.sh nat diff --git a/.github/workflows/unlocked.yml b/.github/workflows/unlocked.yml index 648077f6a1..3bddd4a454 100644 --- a/.github/workflows/unlocked.yml +++ b/.github/workflows/unlocked.yml @@ -49,10 +49,6 @@ jobs: opam depext apron opam install apron - - name: Install sha256sum (macOS) # https://github.com/actions/virtual-environments/issues/90#issuecomment-553279378 - if: ${{ matrix.os == 'macos-latest' }} - run: brew install coreutils - - name: Build run: ./make.sh nat From 303f265cd908d7da4a167a60426ffa5e758ab16e Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Tue, 23 Nov 2021 12:06:12 +0200 Subject: [PATCH 107/402] Symlink 34-localization/04-hh to 36-apron --- tests/regression/34-localization/04-hh.c | 2 ++ tests/regression/36-apron/99-localization-hh.c | 1 + 2 files changed, 3 insertions(+) create mode 120000 tests/regression/36-apron/99-localization-hh.c diff --git a/tests/regression/34-localization/04-hh.c b/tests/regression/34-localization/04-hh.c index 29ef3dc6c7..46bd53ed4c 100644 --- a/tests/regression/34-localization/04-hh.c +++ b/tests/regression/34-localization/04-hh.c @@ -1,4 +1,6 @@ // SKIP PARAM: --enable ana.int.interval --set solver td3 --enable exp.partition-arrays.enabled --set ana.activated "['base','threadid','threadflag','expRelation','mallocWrapper','apron']" --set exp.privatization none --set exp.apron.privatization dummy --set sem.int.signed_overflow assume_none +// This is part of 34-localization, but also symlinked to 36-apron. + // ALSO: --enable ana.int.interval --set solver slr3 --enable exp.partition-arrays.enabled --set ana.activated "['base','threadid','threadflag','expRelation','mallocWrapper','apron']" --set exp.privatization none --set exp.apron.privatization dummy --set sem.int.signed_overflow assume_none // Example from Halbwachs-Henry, SAS 2012 // Localized widening or restart policy should be able to prove that i <= j+3 diff --git a/tests/regression/36-apron/99-localization-hh.c b/tests/regression/36-apron/99-localization-hh.c new file mode 120000 index 0000000000..3e73afc937 --- /dev/null +++ b/tests/regression/36-apron/99-localization-hh.c @@ -0,0 +1 @@ +../34-localization/04-hh.c \ No newline at end of file From 97a89e79ccc53fbe36ace3212dc5462f119fabfe Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Tue, 23 Nov 2021 13:29:27 +0200 Subject: [PATCH 108/402] Rename options incremental.restart.wpoint.* -> exp.solver.td3.restart.wpoint.* --- src/solvers/td3.ml | 5 +++-- src/util/defaults.ml | 4 ++-- tests/regression/34-localization/02-hybrid.c | 2 +- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/solvers/td3.ml b/src/solvers/td3.ml index bb40b5fb81..3ee8ffb123 100644 --- a/src/solvers/td3.ml +++ b/src/solvers/td3.ml @@ -113,12 +113,13 @@ module WP = (* If true, incremental side-effected var restart will only restart destabilized globals (using hack). If false, it will restart all destabilized side-effected vars. *) let restart_only_globals = GobConfig.get_bool "incremental.restart.sided.only-global" in + (* If true, wpoint will be restarted to bot when added. This allows incremental to avoid reusing and republishing imprecise local values due to globals (which get restarted). *) - let restart_wpoint = GobConfig.get_bool "incremental.restart.wpoint.enabled" in + let restart_wpoint = GobConfig.get_bool "exp.solver.td3.restart.wpoint.enabled" in (* If true, each wpoint will be restarted once when added. If false, it will be restarted each time it is added again (wpoints are removed after Narrow). *) - let restart_once = GobConfig.get_bool "incremental.restart.wpoint.once" in + let restart_once = GobConfig.get_bool "exp.solver.td3.restart.wpoint.once" in let restarted_wpoint = HM.create 10 in let incr_verify = GobConfig.get_bool "incremental.verify" in diff --git a/src/util/defaults.ml b/src/util/defaults.ml index a74675956f..a0bde16ec8 100644 --- a/src/util/defaults.ml +++ b/src/util/defaults.ml @@ -158,8 +158,6 @@ let _ = () ; reg Incremental "incremental.compare" "'ast'" "Which comparison should be used for functions? 'ast'/'cfg' (cfg comparison also differentiates which nodes of a function have changed)" ; reg Incremental "incremental.restart.sided.enabled" "true" "TODO" ; reg Incremental "incremental.restart.sided.only-global" "false" "TODO" - ; reg Incremental "incremental.restart.wpoint.enabled" "false" "TODO" - ; reg Incremental "incremental.restart.wpoint.once" "true" "TODO" ; reg Incremental "incremental.verify" "true" "TODO" (* {4 category [Semantics]} *) @@ -208,6 +206,8 @@ let _ = () ; reg Experimental "exp.solver.td3.space" "false" "Should the td3 solver only keep values at widening points?" ; reg Experimental "exp.solver.td3.space_cache" "true" "Should the td3-space solver cache values?" ; reg Experimental "exp.solver.td3.space_restore" "true" "Should the td3-space solver restore values for non-widening-points? Not needed for generating warnings, but needed for inspecting output!" + ; reg Experimental "exp.solver.td3.restart.wpoint.enabled" "false" "TODO" + ; reg Experimental "exp.solver.td3.restart.wpoint.once" "true" "TODO" ; reg Experimental "exp.solver.td3.abort" "false" "TODO" ; reg Experimental "exp.solver.td3.abort-verify" "false" "TODO" ; reg Experimental "exp.solver.slr4.restart_count" "1" "How many times SLR4 is allowed to switch from restarting iteration to increasing iteration." diff --git a/tests/regression/34-localization/02-hybrid.c b/tests/regression/34-localization/02-hybrid.c index 45e746afad..fd4efbd878 100644 --- a/tests/regression/34-localization/02-hybrid.c +++ b/tests/regression/34-localization/02-hybrid.c @@ -1,4 +1,4 @@ -// PARAM: --enable ana.int.interval --set solver td3 --enable incremental.restart.wpoint.enabled --disable incremental.restart.wpoint.once --set sem.int.signed_overflow assume_none +// PARAM: --enable ana.int.interval --set solver td3 --enable exp.solver.td3.restart.wpoint.enabled --disable exp.solver.td3.restart.wpoint.once --set sem.int.signed_overflow assume_none // ALSO: --enable ana.int.interval --set solver sl4 --set sem.int.signed_overflow assume_none // Example from Amato-Scozzari, SAS 2013, based on Halbwachs-Henry, SAS 2012. // Localized narrowing with restart policy should be able to prove that From 810991576f22e2b6bcd4f21fdd48b12ed22699d8 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Tue, 23 Nov 2021 13:30:56 +0200 Subject: [PATCH 109/402] Change TD3 wpoint restarting to be default --- src/util/defaults.ml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/util/defaults.ml b/src/util/defaults.ml index a0bde16ec8..a9485de5e9 100644 --- a/src/util/defaults.ml +++ b/src/util/defaults.ml @@ -206,8 +206,8 @@ let _ = () ; reg Experimental "exp.solver.td3.space" "false" "Should the td3 solver only keep values at widening points?" ; reg Experimental "exp.solver.td3.space_cache" "true" "Should the td3-space solver cache values?" ; reg Experimental "exp.solver.td3.space_restore" "true" "Should the td3-space solver restore values for non-widening-points? Not needed for generating warnings, but needed for inspecting output!" - ; reg Experimental "exp.solver.td3.restart.wpoint.enabled" "false" "TODO" - ; reg Experimental "exp.solver.td3.restart.wpoint.once" "true" "TODO" + ; reg Experimental "exp.solver.td3.restart.wpoint.enabled" "true" "TODO" + ; reg Experimental "exp.solver.td3.restart.wpoint.once" "false" "TODO" ; reg Experimental "exp.solver.td3.abort" "false" "TODO" ; reg Experimental "exp.solver.td3.abort-verify" "false" "TODO" ; reg Experimental "exp.solver.slr4.restart_count" "1" "How many times SLR4 is allowed to switch from restarting iteration to increasing iteration." From 25aa8a9a4c78257d6a93ad96d031eaa1b58bc2f0 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 24 Nov 2021 11:56:15 +0200 Subject: [PATCH 110/402] Add incremental with no global change --- tests/incremental/03-global-nochange.c | 19 +++++++++++++++++++ tests/incremental/03-global-nochange.json | 7 +++++++ tests/incremental/03-global-nochange.patch | 1 + 3 files changed, 27 insertions(+) create mode 100644 tests/incremental/03-global-nochange.c create mode 100644 tests/incremental/03-global-nochange.json create mode 100644 tests/incremental/03-global-nochange.patch diff --git a/tests/incremental/03-global-nochange.c b/tests/incremental/03-global-nochange.c new file mode 100644 index 0000000000..5590fe59fb --- /dev/null +++ b/tests/incremental/03-global-nochange.c @@ -0,0 +1,19 @@ +#include +#include + +int g = 1; + +void* t_fun(void *arg) { + g = 2; + return NULL; +} + +int main() { + pthread_t id; + pthread_create(&id, NULL, t_fun, NULL); // just go multithreaded + + assert(g == 1); // unknown before and after + assert(g == 2); // unknown before and after + assert(g == 0); // fail before and after + return 0; +} \ No newline at end of file diff --git a/tests/incremental/03-global-nochange.json b/tests/incremental/03-global-nochange.json new file mode 100644 index 0000000000..5be265f269 --- /dev/null +++ b/tests/incremental/03-global-nochange.json @@ -0,0 +1,7 @@ +{ + "ana": { + "int": { + "interval": true + } + } +} \ No newline at end of file diff --git a/tests/incremental/03-global-nochange.patch b/tests/incremental/03-global-nochange.patch new file mode 100644 index 0000000000..8b13789179 --- /dev/null +++ b/tests/incremental/03-global-nochange.patch @@ -0,0 +1 @@ + From 821fe223b26b223c32eb83cadebfb1d1df0cd2d9 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 24 Nov 2021 11:56:57 +0200 Subject: [PATCH 111/402] Fix incremental sided restarting all start variables --- src/solvers/td3.ml | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/solvers/td3.ml b/src/solvers/td3.ml index 3ee8ffb123..648b3aa302 100644 --- a/src/solvers/td3.ml +++ b/src/solvers/td3.ml @@ -113,7 +113,7 @@ module WP = (* If true, incremental side-effected var restart will only restart destabilized globals (using hack). If false, it will restart all destabilized side-effected vars. *) let restart_only_globals = GobConfig.get_bool "incremental.restart.sided.only-global" in - + (* If true, wpoint will be restarted to bot when added. This allows incremental to avoid reusing and republishing imprecise local values due to globals (which get restarted). *) let restart_wpoint = GobConfig.get_bool "exp.solver.td3.restart.wpoint.enabled" in @@ -622,8 +622,17 @@ module WP = (* Call side on all globals and functions in the start variables to make sure that changes in the initializers are propagated. * This also destabilizes start functions if their start state changes because of globals that are neither in the start variables nor in the contexts *) List.iter (fun (v,d) -> - if restart_sided then - destabilize v; (* restart side effect from start *) + if restart_sided then ( + match GU.assoc_eq v data.st S.Var.equal with + | Some old_d when not (S.Dom.equal old_d d) -> + ignore (Pretty.printf "Destabilizing changed start var %a\n" S.Var.pretty_trace v); + destabilize v + | _ -> + (* don't restart unchanged start global *) + (* no need to restart added start global (implicit bot before) *) + (* no need to restart removed start global (not used any more)? *) + () + ); (* restart side effect from start *) side v d ) st; From 62d55f621fe857646a28179bee6154790618082f Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 24 Nov 2021 12:28:48 +0200 Subject: [PATCH 112/402] Add incremental sided restarting of removed start variables This is necessary to prune them, removing their warnings and spurious comparison with from scratch. --- src/solvers/td3.ml | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/src/solvers/td3.ml b/src/solvers/td3.ml index 648b3aa302..1c57497a8c 100644 --- a/src/solvers/td3.ml +++ b/src/solvers/td3.ml @@ -619,23 +619,41 @@ module WP = HM.iter (fun k _ -> if Hashtbl.mem marked_for_deletion (S.Var.var_id k) then (ignore (Pretty.printf "marked %a\n" S.Var.pretty_trace k); destabilize k)) stable_copy; (* TODO: don't use string-based nodes *) ); + let restart_and_destabilize x = (* destabilize_with_side doesn't restart x itself *) + HM.replace rho x (S.Dom.bot ()); + destabilize x + in + (* Call side on all globals and functions in the start variables to make sure that changes in the initializers are propagated. * This also destabilizes start functions if their start state changes because of globals that are neither in the start variables nor in the contexts *) List.iter (fun (v,d) -> if restart_sided then ( match GU.assoc_eq v data.st S.Var.equal with | Some old_d when not (S.Dom.equal old_d d) -> - ignore (Pretty.printf "Destabilizing changed start var %a\n" S.Var.pretty_trace v); - destabilize v + ignore (Pretty.printf "Destabilizing and restarting changed start var %a\n" S.Var.pretty_trace v); + restart_and_destabilize v (* restart side effect from start *) | _ -> (* don't restart unchanged start global *) (* no need to restart added start global (implicit bot before) *) - (* no need to restart removed start global (not used any more)? *) + (* restart removed start global below *) () - ); (* restart side effect from start *) + ); side v d ) st; + if restart_sided then ( + List.iter (fun (v, _) -> + match GU.assoc_eq v st S.Var.equal with + | None -> + (* restart removed start global to allow it to be pruned from incremental solution *) + (* this gets rid of its warnings and makes comparing with from scratch sensible *) + ignore (Pretty.printf "Destabilizing and restarting removed start var %a\n" S.Var.pretty_trace v); + restart_and_destabilize v + | _ -> + () + ) data.st + ); + delete_marked stable; delete_marked side_dep; delete_marked side_infl; From d0b15da1ff3a7e82ab0c4d38cf1dc6a8c4c9589c Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Fri, 26 Nov 2021 13:09:15 +0200 Subject: [PATCH 113/402] Fix Access.add_struct bypassing should_warn --- src/analyses/accessAnalysis.ml | 22 ++++++++++++---------- src/domains/access.ml | 22 ++++++++++------------ 2 files changed, 22 insertions(+), 22 deletions(-) diff --git a/src/analyses/accessAnalysis.ml b/src/analyses/accessAnalysis.ml index b69673159e..9a05cb20d5 100644 --- a/src/analyses/accessAnalysis.ml +++ b/src/analyses/accessAnalysis.ml @@ -38,18 +38,20 @@ struct unsafe := 0 let side_access ctx ty lv_opt ls_opt (conf, w, loc, e, lp) = - let (g, o) = lv_opt |? (!none_varinfo, `NoOffset) in - let d = - let open Access in - OM.singleton o ( - TM.singleton ty ( - PM.singleton ls_opt ( - AS.singleton (conf, w, loc, e, lp) + if !GU.should_warn then ( + let (g, o) = lv_opt |? (!none_varinfo, `NoOffset) in + let d = + let open Access in + OM.singleton o ( + TM.singleton ty ( + PM.singleton ls_opt ( + AS.singleton (conf, w, loc, e, lp) + ) ) ) - ) - in - ctx.sideg g d + in + ctx.sideg g d + ) let do_access (ctx: (D.t, G.t, C.t) ctx) (w:bool) (reach:bool) (conf:int) (e:exp) = let open Queries in diff --git a/src/domains/access.ml b/src/domains/access.ml index b6614bfd59..c8e42c54b8 100644 --- a/src/domains/access.ml +++ b/src/domains/access.ml @@ -357,18 +357,16 @@ and distribute_access_exp f w r c = function | _ -> () let add side e w conf vo oo p = - if !Goblintutil.should_warn then begin - let ty = get_val_type e vo oo in - (* let loc = !Tracing.current_loc in *) - (* ignore (printf "add %a %b -- %a\n" d_exp e w d_loc loc); *) - match vo, oo with - | Some v, Some o -> add_struct side e w conf ty (Some (v, remove_idx o)) p - | _ -> - if !unsound && isArithmeticType (type_from_type_offset ty) then - add_struct side e w conf ty None p - else - add_propagate side e w conf ty None p - end + let ty = get_val_type e vo oo in + (* let loc = !Tracing.current_loc in *) + (* ignore (printf "add %a %b -- %a\n" d_exp e w d_loc loc); *) + match vo, oo with + | Some v, Some o -> add_struct side e w conf ty (Some (v, remove_idx o)) p + | _ -> + if !unsound && isArithmeticType (type_from_type_offset ty) then + add_struct side e w conf ty None p + else + add_propagate side e w conf ty None p (* Access table as Lattice. *) From 80b38b29ebf836bc145d2f05948b2021ce35e27b Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Fri, 26 Nov 2021 13:10:30 +0200 Subject: [PATCH 114/402] Change access analysis global leq hack to only apply during postsolving Otherwise this might prevent some side effects from being recorded since everything is already contained? --- src/analyses/accessAnalysis.ml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/analyses/accessAnalysis.ml b/src/analyses/accessAnalysis.ml index 9a05cb20d5..342abc195f 100644 --- a/src/analyses/accessAnalysis.ml +++ b/src/analyses/accessAnalysis.ml @@ -22,7 +22,7 @@ struct struct include Access.OM - let leq _ _ = true (* HACK: to pass verify*) + let leq x y = !GU.postsolving || leq x y (* HACK: to pass verify*) end let none_varinfo = ref dummyFunDec.svar From b7b107eabc96877239d11a9a6375a33f5e2679ba Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Fri, 26 Nov 2021 13:11:49 +0200 Subject: [PATCH 115/402] Fix TD3 sides restart of st not re-triggering st --- src/solvers/td3.ml | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/src/solvers/td3.ml b/src/solvers/td3.ml index 1c57497a8c..86148b5a81 100644 --- a/src/solvers/td3.ml +++ b/src/solvers/td3.ml @@ -497,6 +497,22 @@ module WP = let c = S.increment.changes in List.(Printf.printf "change_info = { unchanged = %d; changed = %d; added = %d; removed = %d }\n" (length c.unchanged) (length c.changed) (length c.added) (length c.removed)); + let restart_leaf x = + if tracing then trace "sol2" "Restarting to bot %a\n" S.Var.pretty_trace x; + ignore (Pretty.printf "Restarting to bot %a\n" S.Var.pretty_trace x); + HM.replace rho x (S.Dom.bot ()); + (* HM.remove rho x; *) + HM.remove wpoint x; (* otherwise gets immediately widened during resolve *) + HM.remove sides x; (* just in case *) + + (* immediately redo "side effect" from st *) + match GU.assoc_eq x st S.Var.equal with + | Some d -> + HM.replace rho x d; + | None -> + () + in + (* destabilize which restarts side-effected vars *) let rec destabilize_with_side ?(front=true) x = if tracing then trace "sol2" "destabilize_with_side %a\n" S.Var.pretty_trace x; @@ -507,12 +523,7 @@ module WP = if not (VS.is_empty w) && (not restart_only_globals || Node.equal (S.Var.node x) (Function Cil.dummyFunDec)) then ( (* restart side-effected var *) - if tracing then trace "sol2" "Restarting to bot %a\n" S.Var.pretty_trace x; - ignore (Pretty.printf "Restarting to bot %a\n" S.Var.pretty_trace x); - HM.replace rho x (S.Dom.bot ()); - (* HM.remove rho x; *) - HM.remove wpoint x; (* otherwise gets immediately widened during resolve *) - HM.remove sides x; (* just in case *) + restart_leaf x; (* destabilize side dep to redo side effects *) VS.iter (fun y -> @@ -620,7 +631,7 @@ module WP = ); let restart_and_destabilize x = (* destabilize_with_side doesn't restart x itself *) - HM.replace rho x (S.Dom.bot ()); + restart_leaf x; destabilize x in From 401d3daa84aef0df6bed12f2a47e8abc4fd69894 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Tue, 30 Nov 2021 18:33:56 +0200 Subject: [PATCH 116/402] Skip failing partitioned array int annotation tests (issue #468) --- .../regression/42-annotated-precision/08-22_01-simple_array.c | 3 ++- .../regression/42-annotated-precision/15-23_01-simple_array.c | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/tests/regression/42-annotated-precision/08-22_01-simple_array.c b/tests/regression/42-annotated-precision/08-22_01-simple_array.c index 8319664bca..d787e48f01 100644 --- a/tests/regression/42-annotated-precision/08-22_01-simple_array.c +++ b/tests/regression/42-annotated-precision/08-22_01-simple_array.c @@ -1,4 +1,5 @@ -// PARAM: --set solver td3 --enable ana.int.interval --enable exp.partition-arrays.enabled --set ana.activated "['base','threadid','threadflag','escape','expRelation','mallocWrapper']" --set exp.privatization none --enable annotation.int.enabled --set ana.int.refinement fixpoint +// SKIP PARAM: --set solver td3 --enable ana.int.interval --enable exp.partition-arrays.enabled --set ana.activated "['base','threadid','threadflag','escape','expRelation','mallocWrapper']" --set exp.privatization none --enable annotation.int.enabled --set ana.int.refinement fixpoint +// skipped because https://github.com/goblint/analyzer/issues/468 int global; int main(void) __attribute__((goblint_precision("no-interval"))) diff --git a/tests/regression/42-annotated-precision/15-23_01-simple_array.c b/tests/regression/42-annotated-precision/15-23_01-simple_array.c index 7ec8bd551b..ca758713a7 100644 --- a/tests/regression/42-annotated-precision/15-23_01-simple_array.c +++ b/tests/regression/42-annotated-precision/15-23_01-simple_array.c @@ -1,4 +1,5 @@ -// PARAM: --set solver td3 --enable ana.int.interval --enable exp.partition-arrays.enabled --set exp.partition-arrays.keep-expr "last" --set ana.activated "['base','threadid','threadflag','escape','expRelation','mallocWrapper']" --set exp.privatization none --enable annotation.int.enabled --set ana.int.refinement fixpoint +// SKIP PARAM: --set solver td3 --enable ana.int.interval --enable exp.partition-arrays.enabled --set exp.partition-arrays.keep-expr "last" --set ana.activated "['base','threadid','threadflag','escape','expRelation','mallocWrapper']" --set exp.privatization none --enable annotation.int.enabled --set ana.int.refinement fixpoint +// skipped because https://github.com/goblint/analyzer/issues/468 int global; int main(void) __attribute__((goblint_precision("no-interval"))) From df980ee90be31caced37e0e59339e89e81f27fcd Mon Sep 17 00:00:00 2001 From: Vesal Vojdani Date: Wed, 1 Dec 2021 17:57:09 +0000 Subject: [PATCH 117/402] EqCon comparison verbose with solverdiff option. --- src/framework/constraints.ml | 3 ++- src/util/precCompare.ml | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/framework/constraints.ml b/src/framework/constraints.ml index 1b97400ce7..421f828528 100644 --- a/src/framework/constraints.ml +++ b/src/framework/constraints.ml @@ -1223,7 +1223,8 @@ struct let compare (name1, name2) vh1 vh2 = Printf.printf "\nComparing precision of %s (left) with %s (right) as EqConstrSys:\n" name1 name2; - let (_, msg) = Compare.compare ~name1 vh1 ~name2 vh2 in + let verbose = get_bool "solverdiffs" in + let (_, msg) = Compare.compare ~verbose ~name1 vh1 ~name2 vh2 in ignore (Pretty.printf "Comparison summary: %t\n" (fun () -> msg)); print_newline (); end diff --git a/src/util/precCompare.ml b/src/util/precCompare.ml index 8108f0eac8..aae61d825e 100644 --- a/src/util/precCompare.ml +++ b/src/util/precCompare.ml @@ -72,7 +72,7 @@ struct let compared = KH.map (fun k (v1, v2) -> let v1 = v1 |? D.bot () in let v2 = v2 |? D.bot () in - CompareD.compare ~name1 ~name2 v1 v2 + CompareD.compare ~verbose ~name1 ~name2 v1 v2 ) kh in KH.iter (fun k (c, msg) -> From 7f4e219639d1f479536237be0f606ffdef8b040e Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 2 Dec 2021 10:24:57 +0200 Subject: [PATCH 118/402] Renumber 36-apron/73-td3-self-abort-complex -> 36/98 --- .../{73-td3-self-abort-complex.c => 98-td3-self-abort-complex.c} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename tests/regression/36-apron/{73-td3-self-abort-complex.c => 98-td3-self-abort-complex.c} (100%) diff --git a/tests/regression/36-apron/73-td3-self-abort-complex.c b/tests/regression/36-apron/98-td3-self-abort-complex.c similarity index 100% rename from tests/regression/36-apron/73-td3-self-abort-complex.c rename to tests/regression/36-apron/98-td3-self-abort-complex.c From 4832cb842006a6393d514faf5e480dc4ec5f057e Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Mon, 6 Dec 2021 16:46:09 +0200 Subject: [PATCH 119/402] Refactor access analysis globals --- src/analyses/accessAnalysis.ml | 39 +++---------- src/domains/access.ml | 104 ++++++++++++++------------------- 2 files changed, 53 insertions(+), 90 deletions(-) diff --git a/src/analyses/accessAnalysis.ml b/src/analyses/accessAnalysis.ml index cc3e362ebe..61ea2f3e0c 100644 --- a/src/analyses/accessAnalysis.ml +++ b/src/analyses/accessAnalysis.ml @@ -20,41 +20,33 @@ struct module G = struct - include Access.OM + include Access.PM let leq x y = !GU.postsolving || leq x y (* HACK: to pass verify*) end - module V = VarinfoV (* TODO: change to abstract type-based struct accesses, etc *) - - let none_varinfo = ref dummyFunDec.svar + module V = Printable.Prod (Access.LVOpt) (Access.T) let safe = ref 0 let vulnerable = ref 0 let unsafe = ref 0 let init marshal = - none_varinfo := GU.create_var @@ makeGlobalVar "__NONE__" voidType; safe := 0; vulnerable := 0; unsafe := 0 let side_access ctx ty lv_opt ls_opt (conf, w, loc, e, lp) = - let (g, o) = lv_opt |? (!none_varinfo, `NoOffset) in if !GU.should_warn then ( let d = let open Access in - OM.singleton o ( - TM.singleton ty ( - PM.singleton ls_opt ( - AS.singleton (conf, w, loc, e, lp) - ) - ) + PM.singleton ls_opt ( + AS.singleton (conf, w, loc, e, lp) ) in - ctx.sideg g d + ctx.sideg (lv_opt, ty) d ) else - ctx.sideg g (G.bot ()) (* HACK: just to pass validation with MCP DomVariantLattice *) + ctx.sideg (lv_opt, ty) (G.bot ()) (* HACK: just to pass validation with MCP DomVariantLattice *) let do_access (ctx: (D.t, G.t, C.t, V.t) ctx) (w:bool) (reach:bool) (conf:int) (e:exp) = let open Queries in @@ -149,12 +141,6 @@ struct ctx.local let body ctx f : D.t = - begin match f.svar.vname with - | "__goblint_dummy_init" -> - ctx.sideg !none_varinfo (G.bot ()) (* make one side effect to None, otherwise verify will always fail due to Lift2 bottom *) - | _ -> - () - end; ctx.local let special ctx lv f arglist : D.t = @@ -224,16 +210,9 @@ struct | WarnGlobal g -> let g: V.t = Obj.obj g in (* ignore (Pretty.printf "WarnGlobal %a\n" CilType.Varinfo.pretty g); *) - let v = - if CilType.Varinfo.equal g !none_varinfo then ( - None - ) - else - Some g - in - let om = ctx.global g in - Access.print_accesses v om; - Access.incr_summary safe vulnerable unsafe v om + let pm = ctx.global g in + Access.print_accesses g pm; + Access.incr_summary safe vulnerable unsafe g pm | _ -> Queries.Result.top q let finalize () = diff --git a/src/domains/access.ml b/src/domains/access.ml index c8e42c54b8..7f6283f457 100644 --- a/src/domains/access.ml +++ b/src/domains/access.ml @@ -402,13 +402,12 @@ struct let printXml f x = BatPrintf.fprintf f "\n\n%s\n\n\n" (XmlUtil.escape (show x)) let to_yojson x = `String (show x) end -module TM = MapDomain.MapBot (T) (PM) module O = struct include Printable.Std type t = offs [@@deriving eq, ord] - let hash _ = 0 (* TODO: not used? *) + let hash _ = 0 (* TODO: add hash *) let pretty = d_offs @@ -416,7 +415,8 @@ struct let printXml f x = BatPrintf.fprintf f "\n\n%s\n\n\n" (XmlUtil.escape (show x)) let to_yojson x = `String (show x) end -module OM = MapDomain.MapBot (O) (TM) +module LV = Printable.Prod (CilType.Varinfo) (O) +module LVOpt = Printable.Option (LV) (struct let name = "NONE" end) let check_accs (prev_r,prev_lp,prev_w) (conf,w,loc,e,lp) = @@ -451,63 +451,47 @@ let check_safe ls accs prev_safe = let is_all_safe = ref true (* Commenting your code is for the WEAK! *) -let incr_summary safe vulnerable unsafe v om = - OM.iter (fun o tm -> - TM.iter (fun ty pm -> - (* ignore(printf "Checking safety of %a:\n" d_memo (ty,lv)); *) - let safety = PM.fold check_safe pm None in - match safety with - | None -> incr safe - | Some n when n >= 100 -> is_all_safe := false; incr unsafe - | Some n -> is_all_safe := false; incr vulnerable - ) tm - ) om - -let print_accesses v om = +let incr_summary safe vulnerable unsafe (lv, ty) pm = + (* ignore(printf "Checking safety of %a:\n" d_memo (ty,lv)); *) + let safety = PM.fold check_safe pm None in + match safety with + | None -> incr safe + | Some n when n >= 100 -> is_all_safe := false; incr unsafe + | Some n -> is_all_safe := false; incr vulnerable + +let print_accesses (lv, ty) pm = let allglobs = get_bool "allglobs" in let debug = get_bool "dbg.debug" in - OM.iter (fun o tm -> - let lv = - match v with - | None -> - assert (o = `NoOffset); - None - | Some v -> - Some (v, o) + let g (ls, acs) = + let h (conf,w,loc,e,lp) = + let d_ls () = match ls with + | None -> Pretty.text " is ok" (* None is used by add_one when access partitions set is empty (not singleton), so access is considered unracing (single-threaded or bullet region)*) + | Some ls when LSSet.is_empty ls -> nil + | Some ls -> text " in " ++ LSSet.pretty () ls in - TM.iter (fun ty pm -> - let g (ls, acs) = - let h (conf,w,loc,e,lp) = - let d_ls () = match ls with - | None -> Pretty.text " is ok" (* None is used by add_one when access partitions set is empty (not singleton), so access is considered unracing (single-threaded or bullet region)*) - | Some ls when LSSet.is_empty ls -> nil - | Some ls -> text " in " ++ LSSet.pretty () ls - in - let atyp = if w then "write" else "read" in - let d_msg () = dprintf "%s%t with %a (conf. %d)" atyp d_ls LSSet.pretty lp conf in - let doc = - if debug then - dprintf "%t (exp: %a)" d_msg d_exp e - else - d_msg () - in - (doc, Some loc) - in - AS.elements acs - |> List.enum - |> Enum.map h - in - let msgs () = - PM.bindings pm - |> List.enum - |> Enum.concat_map g - |> List.of_enum - in - match PM.fold check_safe pm None with - | None -> - if allglobs then - M.msg_group Success ~category:Race "Memory location %a (safe)" d_memo (ty,lv) (msgs ()) - | Some n -> - M.msg_group Warning ~category:Race "Memory location %a (race with conf. %d)" d_memo (ty,lv) n (msgs ()) - ) tm - ) om + let atyp = if w then "write" else "read" in + let d_msg () = dprintf "%s%t with %a (conf. %d)" atyp d_ls LSSet.pretty lp conf in + let doc = + if debug then + dprintf "%t (exp: %a)" d_msg d_exp e + else + d_msg () + in + (doc, Some loc) + in + AS.elements acs + |> List.enum + |> Enum.map h + in + let msgs () = + PM.bindings pm + |> List.enum + |> Enum.concat_map g + |> List.of_enum + in + match PM.fold check_safe pm None with + | None -> + if allglobs then + M.msg_group Success ~category:Race "Memory location %a (safe)" d_memo (ty,lv) (msgs ()) + | Some n -> + M.msg_group Warning ~category:Race "Memory location %a (race with conf. %d)" d_memo (ty,lv) n (msgs ()) From 59de583dba3c3d4a9cf94a9e55919257da9ca261 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Mon, 6 Dec 2021 16:49:55 +0200 Subject: [PATCH 120/402] Add hash to access offsets --- src/domains/access.ml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/domains/access.ml b/src/domains/access.ml index 7f6283f457..a575af41e1 100644 --- a/src/domains/access.ml +++ b/src/domains/access.ml @@ -407,7 +407,10 @@ struct include Printable.Std type t = offs [@@deriving eq, ord] - let hash _ = 0 (* TODO: add hash *) + let rec hash = function + | `NoOffset -> 13 + | `Index os -> 3 + hash os + | `Field (f, os) -> 3 * CilType.Fieldinfo.hash f + hash os let pretty = d_offs From 5fe62042276e0a06ac0bb9f0853307101bd32bbf Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 9 Dec 2021 19:35:57 +0200 Subject: [PATCH 121/402] Rename duplicate tests --- .../02-base/{65-no-eval-on-write.c => 68-no-eval-on-write.c} | 0 .../{66-no-eval-on-write-multi.c => 69-no-eval-on-write-multi.c} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename tests/regression/02-base/{65-no-eval-on-write.c => 68-no-eval-on-write.c} (100%) rename tests/regression/02-base/{66-no-eval-on-write-multi.c => 69-no-eval-on-write-multi.c} (100%) diff --git a/tests/regression/02-base/65-no-eval-on-write.c b/tests/regression/02-base/68-no-eval-on-write.c similarity index 100% rename from tests/regression/02-base/65-no-eval-on-write.c rename to tests/regression/02-base/68-no-eval-on-write.c diff --git a/tests/regression/02-base/66-no-eval-on-write-multi.c b/tests/regression/02-base/69-no-eval-on-write-multi.c similarity index 100% rename from tests/regression/02-base/66-no-eval-on-write-multi.c rename to tests/regression/02-base/69-no-eval-on-write-multi.c From 14e4b42d1356b5491ca7d5ba087ebd7ad6ef34ad Mon Sep 17 00:00:00 2001 From: Julian Erhard Date: Wed, 15 Dec 2021 11:24:28 +0100 Subject: [PATCH 122/402] Store and load data of analyses in incremental runs. In particular, this is needed for reloading the hashtables where varinfos describing dynamically allocated memory are stored. The analyses rely on this data for correctness. --- src/framework/control.ml | 23 +++++++++++++---------- src/incremental/serialize.ml | 4 +++- 2 files changed, 16 insertions(+), 11 deletions(-) diff --git a/src/framework/control.ml b/src/framework/control.ml index 8ef7bf7715..38e3f13547 100644 --- a/src/framework/control.ml +++ b/src/framework/control.ml @@ -298,11 +298,15 @@ struct GU.global_initialization := true; GU.earlyglobs := get_bool "exp.earlyglobs"; - if get_string "load_run" <> "" then ( - Spec.init (Some (Serialize.unmarshal (Filename.concat (get_string "load_run") "spec_marshal"))) - ) - else - Spec.init None; + let marshal = + if get_string "load_run" <> "" then + Some (Serialize.unmarshal (Filename.concat (get_string "load_run") "spec_marshal")) + else if Serialize.results_exist () && get_bool "incremental.load" then + Some (Serialize.load_data Serialize.AnalysisData) + else + None + in + Spec.init marshal; Access.init file; let test_domain (module D: Lattice.S): unit = @@ -508,10 +512,6 @@ struct (* Most warnings happen before durin postsolver, but some happen later (e.g. in finalize), so enable this for the rest (if required by option). *) Goblintutil.should_warn := PostSolverArg.should_warn; - if GobConfig.get_bool "incremental.save" then ( - Serialize.move_tmp_results_to_results () (* Move new incremental results to place where they will be reused *) - ); - let insrt k _ s = match k with | (MyCFG.Function fn,_) -> if not (get_bool "exp.forward") then Set.Int.add fn.svar.vid s else s | (MyCFG.FunctionEntry fn,_) -> if (get_bool "exp.forward") then Set.Int.add fn.svar.vid s else s @@ -643,7 +643,10 @@ struct if get_string "save_run" <> "" then ( Serialize.marshal marshal (Filename.concat (get_string "save_run") "spec_marshal") ); - + if get_bool "incremental.save" then ( + Serialize.store_data marshal Serialize.AnalysisData; + Serialize.move_tmp_results_to_results () + ); if get_bool "dbg.verbose" && get_string "result" <> "none" then print_endline ("Generating output: " ^ get_string "result"); Result.output (lazy local_xml) gh make_global_fast_xml file end diff --git a/src/incremental/serialize.ml b/src/incremental/serialize.ml index d2a91249eb..a9c179fb61 100644 --- a/src/incremental/serialize.ml +++ b/src/incremental/serialize.ml @@ -5,6 +5,7 @@ let goblint_dirname = "incremental_data" let version_map_filename = "version.data" let cil_file_name = "ast.data" let solver_data_file_name = "solver.data" +let analysis_data_file_name = "analysis.data" let results_dir = "results" let results_tmp_dir = "results_tmp" let gob_directory () = let src_dir = !base_directory in @@ -31,12 +32,13 @@ let results_exist () = Sys.file_exists r && Sys.is_directory r (* Convenience enumeration of the different data types we store for incremental analysis, so file-name logic is concentrated in one place *) -type incremental_data_kind = SolverData | CilFile | VersionData +type incremental_data_kind = SolverData | CilFile | VersionData | AnalysisData let type_to_file_name = function | SolverData -> solver_data_file_name | CilFile -> cil_file_name | VersionData -> version_map_filename + | AnalysisData -> analysis_data_file_name (** Loads data for incremental runs from the appropriate file *) let load_data (data_type: incremental_data_kind) = From 84eda518eecbdb7073ea9e80684d3f8f823d281c Mon Sep 17 00:00:00 2001 From: Julian Erhard Date: Wed, 15 Dec 2021 11:26:00 +0100 Subject: [PATCH 123/402] Fix configuration warning string to mention the actual option that is implicitely activated --- src/maingoblint.ml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/maingoblint.ml b/src/maingoblint.ml index 2dc96adf52..cb289b590e 100644 --- a/src/maingoblint.ml +++ b/src/maingoblint.ml @@ -433,7 +433,7 @@ let check_arguments () = if get_bool "ana.base.context.int" && not (get_bool "ana.base.context.non-ptr") then (set_bool "ana.base.context.int" false; warn "ana.base.context.int implicitly disabled by ana.base.context.non-ptr"); (* order matters: non-ptr=false, int=true -> int=false cascades to interval=false with warning *) if get_bool "ana.base.context.interval" && not (get_bool "ana.base.context.int") then (set_bool "ana.base.context.interval" false; warn "ana.base.context.interval implicitly disabled by ana.base.context.int"); - if get_bool "incremental.only-rename" then (set_bool "incremental.load" true; warn "incremental.only-rename implicitly activates incremental.rename-load. Previous AST is loaded for diff and rename, but analyis results are not reused.") + if get_bool "incremental.only-rename" then (set_bool "incremental.load" true; warn "incremental.only-rename implicitly activates incremental.load. Previous AST is loaded for diff and rename, but analyis results are not reused.") let handle_extraspecials () = let funs = get_string_list "exp.extraspecials" in From 1fb025d542fd56ad0ee1de485a5bac64caa7ba7e Mon Sep 17 00:00:00 2001 From: Vesal Vojdani Date: Wed, 15 Dec 2021 15:28:14 +0200 Subject: [PATCH 124/402] Deduplicate tests: rename localization and move (side) restart tests there. --- .../{34-localization => 34-localwn_restart}/01-nested.c | 0 .../{34-localization => 34-localwn_restart}/02-hybrid.c | 0 .../{34-localization => 34-localwn_restart}/03-nested2.c | 0 tests/regression/{34-localization => 34-localwn_restart}/04-hh.c | 0 .../{34-localization => 34-localwn_restart}/05-nested.w.counter.c | 0 .../65-side-restart.c => 34-localwn_restart/11-side-restart.c} | 0 .../12-side-restart-mutual.c} | 0 .../13-side-restart-self.c} | 0 8 files changed, 0 insertions(+), 0 deletions(-) rename tests/regression/{34-localization => 34-localwn_restart}/01-nested.c (100%) rename tests/regression/{34-localization => 34-localwn_restart}/02-hybrid.c (100%) rename tests/regression/{34-localization => 34-localwn_restart}/03-nested2.c (100%) rename tests/regression/{34-localization => 34-localwn_restart}/04-hh.c (100%) rename tests/regression/{34-localization => 34-localwn_restart}/05-nested.w.counter.c (100%) rename tests/regression/{02-base/65-side-restart.c => 34-localwn_restart/11-side-restart.c} (100%) rename tests/regression/{02-base/66-side-restart-mutual.c => 34-localwn_restart/12-side-restart-mutual.c} (100%) rename tests/regression/{02-base/67-side-restart-self.c => 34-localwn_restart/13-side-restart-self.c} (100%) diff --git a/tests/regression/34-localization/01-nested.c b/tests/regression/34-localwn_restart/01-nested.c similarity index 100% rename from tests/regression/34-localization/01-nested.c rename to tests/regression/34-localwn_restart/01-nested.c diff --git a/tests/regression/34-localization/02-hybrid.c b/tests/regression/34-localwn_restart/02-hybrid.c similarity index 100% rename from tests/regression/34-localization/02-hybrid.c rename to tests/regression/34-localwn_restart/02-hybrid.c diff --git a/tests/regression/34-localization/03-nested2.c b/tests/regression/34-localwn_restart/03-nested2.c similarity index 100% rename from tests/regression/34-localization/03-nested2.c rename to tests/regression/34-localwn_restart/03-nested2.c diff --git a/tests/regression/34-localization/04-hh.c b/tests/regression/34-localwn_restart/04-hh.c similarity index 100% rename from tests/regression/34-localization/04-hh.c rename to tests/regression/34-localwn_restart/04-hh.c diff --git a/tests/regression/34-localization/05-nested.w.counter.c b/tests/regression/34-localwn_restart/05-nested.w.counter.c similarity index 100% rename from tests/regression/34-localization/05-nested.w.counter.c rename to tests/regression/34-localwn_restart/05-nested.w.counter.c diff --git a/tests/regression/02-base/65-side-restart.c b/tests/regression/34-localwn_restart/11-side-restart.c similarity index 100% rename from tests/regression/02-base/65-side-restart.c rename to tests/regression/34-localwn_restart/11-side-restart.c diff --git a/tests/regression/02-base/66-side-restart-mutual.c b/tests/regression/34-localwn_restart/12-side-restart-mutual.c similarity index 100% rename from tests/regression/02-base/66-side-restart-mutual.c rename to tests/regression/34-localwn_restart/12-side-restart-mutual.c diff --git a/tests/regression/02-base/67-side-restart-self.c b/tests/regression/34-localwn_restart/13-side-restart-self.c similarity index 100% rename from tests/regression/02-base/67-side-restart-self.c rename to tests/regression/34-localwn_restart/13-side-restart-self.c From 94504caa7644168b6003d28befa6f6b176bc6fb8 Mon Sep 17 00:00:00 2001 From: Vesal Vojdani Date: Wed, 15 Dec 2021 15:35:42 +0200 Subject: [PATCH 125/402] Deduplicate remaining tests. --- .../{67-no-int-context-option.c => 64-no-int-context-option.c} | 0 .../02-base/{68-int-context-option.c => 65-int-context-option.c} | 0 tests/regression/02-base/{64-enums-minmax.c => 67-enums-minmax.c} | 0 3 files changed, 0 insertions(+), 0 deletions(-) rename tests/regression/02-base/{67-no-int-context-option.c => 64-no-int-context-option.c} (100%) rename tests/regression/02-base/{68-int-context-option.c => 65-int-context-option.c} (100%) rename tests/regression/02-base/{64-enums-minmax.c => 67-enums-minmax.c} (100%) diff --git a/tests/regression/02-base/67-no-int-context-option.c b/tests/regression/02-base/64-no-int-context-option.c similarity index 100% rename from tests/regression/02-base/67-no-int-context-option.c rename to tests/regression/02-base/64-no-int-context-option.c diff --git a/tests/regression/02-base/68-int-context-option.c b/tests/regression/02-base/65-int-context-option.c similarity index 100% rename from tests/regression/02-base/68-int-context-option.c rename to tests/regression/02-base/65-int-context-option.c diff --git a/tests/regression/02-base/64-enums-minmax.c b/tests/regression/02-base/67-enums-minmax.c similarity index 100% rename from tests/regression/02-base/64-enums-minmax.c rename to tests/regression/02-base/67-enums-minmax.c From 558cefe46de6f9d35984abe44e70d6503bed904f Mon Sep 17 00:00:00 2001 From: Vesal Vojdani Date: Wed, 15 Dec 2021 15:45:16 +0200 Subject: [PATCH 126/402] Ouch, update symlinked test. --- tests/regression/36-apron/99-localization-hh.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/regression/36-apron/99-localization-hh.c b/tests/regression/36-apron/99-localization-hh.c index 3e73afc937..b111e77e97 120000 --- a/tests/regression/36-apron/99-localization-hh.c +++ b/tests/regression/36-apron/99-localization-hh.c @@ -1 +1 @@ -../34-localization/04-hh.c \ No newline at end of file +../34-localwn_restart/04-hh.c \ No newline at end of file From be41c270b9b111574aabadf20d4eb77a395974ff Mon Sep 17 00:00:00 2001 From: Vesal Vojdani Date: Wed, 15 Dec 2021 17:25:45 +0200 Subject: [PATCH 127/402] Add minimized test where abort fails. --- .../21-restart_abort_aget.c | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 tests/regression/34-localwn_restart/21-restart_abort_aget.c diff --git a/tests/regression/34-localwn_restart/21-restart_abort_aget.c b/tests/regression/34-localwn_restart/21-restart_abort_aget.c new file mode 100644 index 0000000000..d0d2182a9a --- /dev/null +++ b/tests/regression/34-localwn_restart/21-restart_abort_aget.c @@ -0,0 +1,23 @@ +// SKIP PARAM: --enable exp.solver.td3.restart.wpoint.enabled --enable exp.solver.td3.abort + +#include +struct a { + int b; +} c(), *f; + +int g; +void d(); +void e(); + +int main() { + void *h = calloc(1, sizeof(struct a)); + f = h; + d(e); + while (1) { + g = c; + if (c) + break; + f->b = 0; + } + d(h); +} \ No newline at end of file From f69735d624063d718828a4c85fed6b09db3dc605 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 15 Dec 2021 17:46:40 +0200 Subject: [PATCH 128/402] Fix TD3 wpoint restart not destabilizing enough for abort --- src/solvers/td3.ml | 6 +++++- tests/regression/34-localwn_restart/21-restart_abort_aget.c | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/solvers/td3.ml b/src/solvers/td3.ml index 94c59ec9b5..f6d8ceb926 100644 --- a/src/solvers/td3.ml +++ b/src/solvers/td3.ml @@ -375,7 +375,11 @@ module WP = if not (restart_once && HM.mem restarted_wpoint y) then ( if tracing then trace "sol2" "wpoint restart %a ## %a\n" S.Var.pretty_trace y S.Dom.pretty (HM.find_default rho y (S.Dom.bot ())); HM.replace rho y (S.Dom.bot ()); - destabilize y; (* required for abort (front) *) + HM.replace called_changed y (); (* just in case *) + (* required for abort (front), for 34-localwn_restart/21-restart_abort_aget *) + HM.remove stable y; + HM.remove superstable y; + destabilize y; if restart_once then (* avoid populating hashtable unnecessarily *) HM.replace restarted_wpoint y (); ) diff --git a/tests/regression/34-localwn_restart/21-restart_abort_aget.c b/tests/regression/34-localwn_restart/21-restart_abort_aget.c index d0d2182a9a..902d4f0ef5 100644 --- a/tests/regression/34-localwn_restart/21-restart_abort_aget.c +++ b/tests/regression/34-localwn_restart/21-restart_abort_aget.c @@ -1,4 +1,4 @@ -// SKIP PARAM: --enable exp.solver.td3.restart.wpoint.enabled --enable exp.solver.td3.abort +// PARAM: --enable exp.solver.td3.restart.wpoint.enabled --enable exp.solver.td3.abort #include struct a { From c6db029dc695f62ce100f0c4b10f480929818d16 Mon Sep 17 00:00:00 2001 From: Vesal Vojdani Date: Wed, 15 Dec 2021 21:15:18 +0200 Subject: [PATCH 129/402] [skip ci] Add abort fixpoint not reached test. --- tests/incremental/02-abort/01-abort_aget.c | 15 ++++++ tests/incremental/02-abort/01-abort_aget.json | 46 +++++++++++++++++++ .../incremental/02-abort/01-abort_aget.patch | 10 ++++ 3 files changed, 71 insertions(+) create mode 100644 tests/incremental/02-abort/01-abort_aget.c create mode 100644 tests/incremental/02-abort/01-abort_aget.json create mode 100644 tests/incremental/02-abort/01-abort_aget.patch diff --git a/tests/incremental/02-abort/01-abort_aget.c b/tests/incremental/02-abort/01-abort_aget.c new file mode 100644 index 0000000000..277d5ccd49 --- /dev/null +++ b/tests/incremental/02-abort/01-abort_aget.c @@ -0,0 +1,15 @@ +// SKIP + +int a; +void b(); + +void c() {} + +int d() { + return 0; +} + +main() { + b(d); + c(); +} \ No newline at end of file diff --git a/tests/incremental/02-abort/01-abort_aget.json b/tests/incremental/02-abort/01-abort_aget.json new file mode 100644 index 0000000000..be30abbf3c --- /dev/null +++ b/tests/incremental/02-abort/01-abort_aget.json @@ -0,0 +1,46 @@ +{ + "ana": { + "int": { + "interval": true + } + }, + "sem": { + "int": { + "signed_overflow": "assume_none" + }, + "unknown_function": { + "invalidate": { + "globals": false + } + } + }, + "dbg": { + "debug": false + }, + "exp": { + "solver": { + "td3": { + "restart": { + "wpoint": { + "enabled": false, + "once": true + } + }, + "abort": true, + "abort-verify": false + } + } + }, + "incremental": { + "reluctant": { + "on": false, + "compare": "equal" + }, + "restart": { + "sided": { + "enabled": true, + "only-global": false + } + } + } +} diff --git a/tests/incremental/02-abort/01-abort_aget.patch b/tests/incremental/02-abort/01-abort_aget.patch new file mode 100644 index 0000000000..de46522b79 --- /dev/null +++ b/tests/incremental/02-abort/01-abort_aget.patch @@ -0,0 +1,10 @@ +diff --git a/tests/incremental/02-abort/11-abort_aget.c b/tests/incremental/02-abort/11-abort_aget.c +@@ -6,7 +6,7 @@ void b(); + void c() {} + + int d() { +- return 0; ++ return 1; + } + + main() { From 38049768c5a7e86ed4cfe681d7eea750484d70e1 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 16 Dec 2021 11:23:14 +0200 Subject: [PATCH 130/402] Fix TD3 sided restarting not adding side_dep to front for abort --- src/solvers/td3.ml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/solvers/td3.ml b/src/solvers/td3.ml index f6d8ceb926..a265f80939 100644 --- a/src/solvers/td3.ml +++ b/src/solvers/td3.ml @@ -537,6 +537,9 @@ module WP = (* restart side-effected var *) restart_leaf x; + (* add side_dep to front to prevent them from being aborted *) + destabilize_front ~front:true x w; + (* destabilize side dep to redo side effects *) VS.iter (fun y -> if tracing then trace "sol2" "destabilize_with_side %a side_dep %a\n" S.Var.pretty_trace x S.Var.pretty_trace y; From 65d1ea1b7adbd5363a124719f8e852f300a85102 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 16 Dec 2021 13:18:28 +0200 Subject: [PATCH 131/402] Add options for TD3 narrow rhs reuse --- src/solvers/td3.ml | 16 ++++++++++++++-- src/util/defaults.ml | 2 ++ 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/src/solvers/td3.ml b/src/solvers/td3.ml index a265f80939..df93122c8b 100644 --- a/src/solvers/td3.ml +++ b/src/solvers/td3.ml @@ -105,6 +105,9 @@ module WP = let wpoint = data.wpoint in let stable = data.stable in + let narrow_reuse = GobConfig.get_bool "exp.solver.td3.narrow-reuse" in + let narrow_reuse_verify = GobConfig.get_bool "exp.solver.td3.narrow-reuse-verify" in + let side_dep = data.side_dep in let side_infl = data.side_infl in (* If true, incremental destabilized side-effected vars will be restarted. @@ -239,8 +242,10 @@ module WP = in let tmp = match reuse_eq with - | Some d -> d - | None -> + | Some d when narrow_reuse && not narrow_reuse_verify -> + if tracing then trace "sol2" "eq reused %a\n" S.Var.pretty_trace x; + d + | _ -> try if abort && abort_verify then ( (* collect dep vals for x *) @@ -263,6 +268,13 @@ module WP = (* prev_dep_vals remain the same *) HM.find rho x (* old *) in + begin match reuse_eq with + | Some reuse_eq when narrow_reuse_verify && not (S.Dom.equal tmp reuse_eq) -> + if M.tracing then trace "sol2" "reuse eq neq %a: %a %a\n" S.Var.pretty_trace x S.Dom.pretty reuse_eq S.Dom.pretty tmp; + failwith (Pretty.sprint ~width:max_int (Pretty.dprintf "TD3 narrow reuse verify: should not reuse %a" S.Var.pretty_trace x)) + | _ -> + () + end; let new_eq = tmp in (* let tmp = if GobConfig.get_bool "ana.opt.hashcons" then S.Dom.join (S.Dom.bot ()) tmp else tmp in (* Call hashcons via dummy join so that the tag of the rhs value is up to date. Otherwise we might get the same value as old, but still with a different tag (because no lattice operation was called after a change), and since Printable.HConsed.equal just looks at the tag, we would uneccessarily destabilize below. Seems like this does not happen. *) *) if tracing then trace "sol" "Var: %a\n" S.Var.pretty_trace x ; diff --git a/src/util/defaults.ml b/src/util/defaults.ml index 5ed10b3f0c..fdb15a1615 100644 --- a/src/util/defaults.ml +++ b/src/util/defaults.ml @@ -237,6 +237,8 @@ let _ = () ; reg Experimental "exp.solver.td3.space" "false" "Should the td3 solver only keep values at widening points?" ; reg Experimental "exp.solver.td3.space_cache" "true" "Should the td3-space solver cache values?" ; reg Experimental "exp.solver.td3.space_restore" "true" "Should the td3-space solver restore values for non-widening-points? Not needed for generating warnings, but needed for inspecting output!" + ; reg Experimental "exp.solver.td3.narrow-reuse" "true" "TODO" + ; reg Experimental "exp.solver.td3.narrow-reuse-verify" "false" "TODO" ; reg Experimental "exp.solver.td3.restart.wpoint.enabled" "true" "TODO" ; reg Experimental "exp.solver.td3.restart.wpoint.once" "false" "TODO" ; reg Experimental "exp.solver.td3.abort" "false" "TODO" From 151f137339823571335b9f56d791f4d075f54949 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 16 Dec 2021 13:21:11 +0200 Subject: [PATCH 132/402] Add narrow reuse stats to TD3 --- src/maingoblint.ml | 2 +- src/solvers/td3.ml | 1 + src/util/goblintutil.ml | 1 + 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/maingoblint.ml b/src/maingoblint.ml index f82fb07e60..09c7bb2874 100644 --- a/src/maingoblint.ml +++ b/src/maingoblint.ml @@ -320,7 +320,7 @@ let merge_preprocessed cpp_file_names = let do_stats () = if get_bool "printstats" then ( print_newline (); - ignore (Pretty.printf "vars = %d evals = %d aborts = %d\n" !Goblintutil.vars !Goblintutil.evals !Goblintutil.aborts); + ignore (Pretty.printf "vars = %d evals = %d narrow_reuses = %d aborts = %d\n" !Goblintutil.vars !Goblintutil.evals !Goblintutil.narrow_reuses !Goblintutil.aborts); print_newline (); Stats.print (Messages.get_out "timing" Legacy.stderr) "Timings:\n"; flush_all () diff --git a/src/solvers/td3.ml b/src/solvers/td3.ml index df93122c8b..775841f883 100644 --- a/src/solvers/td3.ml +++ b/src/solvers/td3.ml @@ -244,6 +244,7 @@ module WP = match reuse_eq with | Some d when narrow_reuse && not narrow_reuse_verify -> if tracing then trace "sol2" "eq reused %a\n" S.Var.pretty_trace x; + incr Goblintutil.narrow_reuses; d | _ -> try diff --git a/src/util/goblintutil.ml b/src/util/goblintutil.ml index 1fc34db870..72c7db9b36 100644 --- a/src/util/goblintutil.ml +++ b/src/util/goblintutil.ml @@ -117,6 +117,7 @@ let seconds_of_duration_string = let vars = ref 0 let evals = ref 0 +let narrow_reuses = ref 0 let aborts = ref 0 (* print GC statistics; taken from Cil.Stats.print which also includes timing; there's also Gc.print_stat, but it's in words instead of MB and more info than we want (also slower than quick_stat since it goes through the heap) *) From aa2135d45c6b7d84c84b1462a38ea396e94e7760 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 16 Dec 2021 13:25:42 +0200 Subject: [PATCH 133/402] Fix TD3 abort to not reuse aborted rhs for narrowing switch optimization --- src/solvers/td3.ml | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/src/solvers/td3.ml b/src/solvers/td3.ml index 775841f883..b3fcc0a851 100644 --- a/src/solvers/td3.ml +++ b/src/solvers/td3.ml @@ -240,12 +240,12 @@ module WP = let (d, changed) = eval l x y in d in - let tmp = + let (tmp, aborted) = match reuse_eq with | Some d when narrow_reuse && not narrow_reuse_verify -> if tracing then trace "sol2" "eq reused %a\n" S.Var.pretty_trace x; incr Goblintutil.narrow_reuses; - d + (d, false) | _ -> try if abort && abort_verify then ( @@ -258,16 +258,16 @@ module WP = in let tmp = eq x eval' (side ~x) in HM.replace prev_dep_vals x new_dep_vals_x; - tmp + (tmp, false) ) else - eq x eval' (side ~x) + (eq x eval' (side ~x), false) with AbortEq -> abort_rhs_event x; if tracing then trace "sol2" "eq aborted %a\n" S.Var.pretty_trace x; HM.remove destab_dep x; (* TODO: safe to remove here? doesn't prevent some aborts? *) (* prev_dep_vals remain the same *) - HM.find rho x (* old *) + (HM.find rho x, true) (* old *) in begin match reuse_eq with | Some reuse_eq when narrow_reuse_verify && not (S.Dom.equal tmp reuse_eq) -> @@ -340,7 +340,12 @@ module WP = if tracing then trace "sol2" "stable remove %a\n" S.Var.pretty_trace x; HM.remove stable x; HM.remove superstable x; - (solve[@tailcall]) ~reuse_eq:new_eq ~abortable:false x Narrow changed + let reuse_eq = if not aborted then + Some new_eq + else + None (* TODO: for some reason cannot reuse aborted rhs, see 34-localwn_restart/02-hybrid *) + in + (solve[@tailcall]) ?reuse_eq ~abortable:false x Narrow changed ) else if not space && (not term || phase = Narrow) then ( (* this makes e.g. nested loops precise, ex. tests/regression/34-localization/01-nested.c - if we do not remove wpoint, the inner loop head will stay a wpoint and widen the outer loop variable. *) if tracing then trace "sol2" "solve removing wpoint %a (%b)\n" S.Var.pretty_trace x (HM.mem wpoint x); HM.remove wpoint x; From fc5a06c55f690d606a9fcd6c5abc93cb6200c000 Mon Sep 17 00:00:00 2001 From: Vesal Vojdani Date: Thu, 16 Dec 2021 19:40:27 +0200 Subject: [PATCH 134/402] Remove skip from passing test. --- tests/incremental/02-abort/01-abort_aget.c | 2 -- tests/incremental/02-abort/01-abort_aget.patch | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/tests/incremental/02-abort/01-abort_aget.c b/tests/incremental/02-abort/01-abort_aget.c index 277d5ccd49..2520756134 100644 --- a/tests/incremental/02-abort/01-abort_aget.c +++ b/tests/incremental/02-abort/01-abort_aget.c @@ -1,5 +1,3 @@ -// SKIP - int a; void b(); diff --git a/tests/incremental/02-abort/01-abort_aget.patch b/tests/incremental/02-abort/01-abort_aget.patch index de46522b79..8295ae3f70 100644 --- a/tests/incremental/02-abort/01-abort_aget.patch +++ b/tests/incremental/02-abort/01-abort_aget.patch @@ -1,5 +1,5 @@ diff --git a/tests/incremental/02-abort/11-abort_aget.c b/tests/incremental/02-abort/11-abort_aget.c -@@ -6,7 +6,7 @@ void b(); +@@ -4,7 +4,7 @@ void b(); void c() {} int d() { From ae7833bbcf7dc6d20879a00a45612b7d292bce83 Mon Sep 17 00:00:00 2001 From: Vesal Vojdani Date: Thu, 16 Dec 2021 19:47:49 +0200 Subject: [PATCH 135/402] Add another abort FP fail. --- tests/incremental/02-abort/02-abort-smtprc.c | 37 +++++++++++++++ .../incremental/02-abort/02-abort-smtprc.json | 46 +++++++++++++++++++ .../02-abort/02-abort-smtprc.patch | 10 ++++ 3 files changed, 93 insertions(+) create mode 100644 tests/incremental/02-abort/02-abort-smtprc.c create mode 100644 tests/incremental/02-abort/02-abort-smtprc.json create mode 100644 tests/incremental/02-abort/02-abort-smtprc.patch diff --git a/tests/incremental/02-abort/02-abort-smtprc.c b/tests/incremental/02-abort/02-abort-smtprc.c new file mode 100644 index 0000000000..e6c011c2ee --- /dev/null +++ b/tests/incremental/02-abort/02-abort-smtprc.c @@ -0,0 +1,37 @@ +// SKIP +struct { + unsigned a; +} b; +int c; +void d(); +void f(); +void h(); +int i(); +void main() { + int e; + if (e) + b.a++; + h(); +} +void j() { + int g = 0; + i(&g); +} +void h() { + if (b.a) + d(j); +} +void k() {} +int i(int l) { + int m; + while (m) { + f(l); + if (c) + return (-1); + d(l); + } +} +void f() { + d(b); + k(); +} \ No newline at end of file diff --git a/tests/incremental/02-abort/02-abort-smtprc.json b/tests/incremental/02-abort/02-abort-smtprc.json new file mode 100644 index 0000000000..be30abbf3c --- /dev/null +++ b/tests/incremental/02-abort/02-abort-smtprc.json @@ -0,0 +1,46 @@ +{ + "ana": { + "int": { + "interval": true + } + }, + "sem": { + "int": { + "signed_overflow": "assume_none" + }, + "unknown_function": { + "invalidate": { + "globals": false + } + } + }, + "dbg": { + "debug": false + }, + "exp": { + "solver": { + "td3": { + "restart": { + "wpoint": { + "enabled": false, + "once": true + } + }, + "abort": true, + "abort-verify": false + } + } + }, + "incremental": { + "reluctant": { + "on": false, + "compare": "equal" + }, + "restart": { + "sided": { + "enabled": true, + "only-global": false + } + } + } +} diff --git a/tests/incremental/02-abort/02-abort-smtprc.patch b/tests/incremental/02-abort/02-abort-smtprc.patch new file mode 100644 index 0000000000..ff3bff7a0d --- /dev/null +++ b/tests/incremental/02-abort/02-abort-smtprc.patch @@ -0,0 +1,10 @@ +diff --git a/tests/incremental/02-abort/02-abort-smtprc.c b/tests/incremental/02-abort/02-abort-smtprc.c +@@ -26,7 +26,7 @@ int i(int l) { + while (m) { + f(l); + if (c) +- return (-1); ++ return (-2); + d(l); + } + } From de3031d9bf82518dfb9319216d0dacdf2e979cdd Mon Sep 17 00:00:00 2001 From: Vesal Vojdani Date: Thu, 16 Dec 2021 20:06:00 +0200 Subject: [PATCH 136/402] Move incremental tests into subdir. --- tests/incremental/{ => 01-restart}/00-justglob.c | 0 tests/incremental/{ => 01-restart}/00-justglob.json | 0 tests/incremental/{ => 01-restart}/00-justglob.patch | 0 .../{03-global-nochange.c => 01-restart/01-global-nochange.c} | 0 .../{03-global-change.json => 01-restart/01-global-nochange.json} | 0 .../01-global-nochange.patch} | 0 tests/incremental/{ => 01-restart}/02-global-remove.c | 0 tests/incremental/{ => 01-restart}/02-global-remove.json | 0 tests/incremental/{ => 01-restart}/02-global-remove.patch | 0 tests/incremental/{ => 01-restart}/03-global-change.c | 0 .../{03-global-nochange.json => 01-restart/03-global-change.json} | 0 tests/incremental/{ => 01-restart}/03-global-change.patch | 0 tests/incremental/{ => 01-restart}/04-global-add.c | 0 tests/incremental/{ => 01-restart}/04-global-add.json | 0 tests/incremental/{ => 01-restart}/04-global-add.patch | 0 tests/incremental/{ => 01-restart}/05-local-wpoint.c | 0 tests/incremental/{ => 01-restart}/05-local-wpoint.json | 0 tests/incremental/{ => 01-restart}/05-local-wpoint.patch | 0 tests/incremental/{ => 01-restart}/06-local-wpoint-read.c | 0 tests/incremental/{ => 01-restart}/06-local-wpoint-read.json | 0 tests/incremental/{ => 01-restart}/06-local-wpoint-read.patch | 0 tests/incremental/{ => 01-restart}/07-hashcons.c | 0 tests/incremental/{ => 01-restart}/07-hashcons.json | 0 tests/incremental/{ => 01-restart}/07-hashcons.patch | 0 tests/incremental/{ => 01-restart}/08-side-restart.c | 0 tests/incremental/{ => 01-restart}/08-side-restart.json | 0 tests/incremental/{ => 01-restart}/08-side-restart.patch | 0 .../incremental/{06-call-remove.c => 01-restart/09-call-remove.c} | 0 .../{06-call-remove.json => 01-restart/09-call-remove.json} | 0 .../{06-call-remove.patch => 01-restart/09-call-remove.patch} | 0 .../{05-paper-example.c => 01-restart/11-paper-example.c} | 0 .../{05-paper-example.json => 01-restart/11-paper-example.json} | 0 .../{05-paper-example.patch => 01-restart/11-paper-example.patch} | 0 tests/incremental/{ => 01-restart}/48-local-wpoint-funcall.c | 0 tests/incremental/{ => 01-restart}/48-local-wpoint-funcall.json | 0 tests/incremental/{ => 01-restart}/48-local-wpoint-funcall.patch | 0 36 files changed, 0 insertions(+), 0 deletions(-) rename tests/incremental/{ => 01-restart}/00-justglob.c (100%) rename tests/incremental/{ => 01-restart}/00-justglob.json (100%) rename tests/incremental/{ => 01-restart}/00-justglob.patch (100%) rename tests/incremental/{03-global-nochange.c => 01-restart/01-global-nochange.c} (100%) rename tests/incremental/{03-global-change.json => 01-restart/01-global-nochange.json} (100%) rename tests/incremental/{03-global-nochange.patch => 01-restart/01-global-nochange.patch} (100%) rename tests/incremental/{ => 01-restart}/02-global-remove.c (100%) rename tests/incremental/{ => 01-restart}/02-global-remove.json (100%) rename tests/incremental/{ => 01-restart}/02-global-remove.patch (100%) rename tests/incremental/{ => 01-restart}/03-global-change.c (100%) rename tests/incremental/{03-global-nochange.json => 01-restart/03-global-change.json} (100%) rename tests/incremental/{ => 01-restart}/03-global-change.patch (100%) rename tests/incremental/{ => 01-restart}/04-global-add.c (100%) rename tests/incremental/{ => 01-restart}/04-global-add.json (100%) rename tests/incremental/{ => 01-restart}/04-global-add.patch (100%) rename tests/incremental/{ => 01-restart}/05-local-wpoint.c (100%) rename tests/incremental/{ => 01-restart}/05-local-wpoint.json (100%) rename tests/incremental/{ => 01-restart}/05-local-wpoint.patch (100%) rename tests/incremental/{ => 01-restart}/06-local-wpoint-read.c (100%) rename tests/incremental/{ => 01-restart}/06-local-wpoint-read.json (100%) rename tests/incremental/{ => 01-restart}/06-local-wpoint-read.patch (100%) rename tests/incremental/{ => 01-restart}/07-hashcons.c (100%) rename tests/incremental/{ => 01-restart}/07-hashcons.json (100%) rename tests/incremental/{ => 01-restart}/07-hashcons.patch (100%) rename tests/incremental/{ => 01-restart}/08-side-restart.c (100%) rename tests/incremental/{ => 01-restart}/08-side-restart.json (100%) rename tests/incremental/{ => 01-restart}/08-side-restart.patch (100%) rename tests/incremental/{06-call-remove.c => 01-restart/09-call-remove.c} (100%) rename tests/incremental/{06-call-remove.json => 01-restart/09-call-remove.json} (100%) rename tests/incremental/{06-call-remove.patch => 01-restart/09-call-remove.patch} (100%) rename tests/incremental/{05-paper-example.c => 01-restart/11-paper-example.c} (100%) rename tests/incremental/{05-paper-example.json => 01-restart/11-paper-example.json} (100%) rename tests/incremental/{05-paper-example.patch => 01-restart/11-paper-example.patch} (100%) rename tests/incremental/{ => 01-restart}/48-local-wpoint-funcall.c (100%) rename tests/incremental/{ => 01-restart}/48-local-wpoint-funcall.json (100%) rename tests/incremental/{ => 01-restart}/48-local-wpoint-funcall.patch (100%) diff --git a/tests/incremental/00-justglob.c b/tests/incremental/01-restart/00-justglob.c similarity index 100% rename from tests/incremental/00-justglob.c rename to tests/incremental/01-restart/00-justglob.c diff --git a/tests/incremental/00-justglob.json b/tests/incremental/01-restart/00-justglob.json similarity index 100% rename from tests/incremental/00-justglob.json rename to tests/incremental/01-restart/00-justglob.json diff --git a/tests/incremental/00-justglob.patch b/tests/incremental/01-restart/00-justglob.patch similarity index 100% rename from tests/incremental/00-justglob.patch rename to tests/incremental/01-restart/00-justglob.patch diff --git a/tests/incremental/03-global-nochange.c b/tests/incremental/01-restart/01-global-nochange.c similarity index 100% rename from tests/incremental/03-global-nochange.c rename to tests/incremental/01-restart/01-global-nochange.c diff --git a/tests/incremental/03-global-change.json b/tests/incremental/01-restart/01-global-nochange.json similarity index 100% rename from tests/incremental/03-global-change.json rename to tests/incremental/01-restart/01-global-nochange.json diff --git a/tests/incremental/03-global-nochange.patch b/tests/incremental/01-restart/01-global-nochange.patch similarity index 100% rename from tests/incremental/03-global-nochange.patch rename to tests/incremental/01-restart/01-global-nochange.patch diff --git a/tests/incremental/02-global-remove.c b/tests/incremental/01-restart/02-global-remove.c similarity index 100% rename from tests/incremental/02-global-remove.c rename to tests/incremental/01-restart/02-global-remove.c diff --git a/tests/incremental/02-global-remove.json b/tests/incremental/01-restart/02-global-remove.json similarity index 100% rename from tests/incremental/02-global-remove.json rename to tests/incremental/01-restart/02-global-remove.json diff --git a/tests/incremental/02-global-remove.patch b/tests/incremental/01-restart/02-global-remove.patch similarity index 100% rename from tests/incremental/02-global-remove.patch rename to tests/incremental/01-restart/02-global-remove.patch diff --git a/tests/incremental/03-global-change.c b/tests/incremental/01-restart/03-global-change.c similarity index 100% rename from tests/incremental/03-global-change.c rename to tests/incremental/01-restart/03-global-change.c diff --git a/tests/incremental/03-global-nochange.json b/tests/incremental/01-restart/03-global-change.json similarity index 100% rename from tests/incremental/03-global-nochange.json rename to tests/incremental/01-restart/03-global-change.json diff --git a/tests/incremental/03-global-change.patch b/tests/incremental/01-restart/03-global-change.patch similarity index 100% rename from tests/incremental/03-global-change.patch rename to tests/incremental/01-restart/03-global-change.patch diff --git a/tests/incremental/04-global-add.c b/tests/incremental/01-restart/04-global-add.c similarity index 100% rename from tests/incremental/04-global-add.c rename to tests/incremental/01-restart/04-global-add.c diff --git a/tests/incremental/04-global-add.json b/tests/incremental/01-restart/04-global-add.json similarity index 100% rename from tests/incremental/04-global-add.json rename to tests/incremental/01-restart/04-global-add.json diff --git a/tests/incremental/04-global-add.patch b/tests/incremental/01-restart/04-global-add.patch similarity index 100% rename from tests/incremental/04-global-add.patch rename to tests/incremental/01-restart/04-global-add.patch diff --git a/tests/incremental/05-local-wpoint.c b/tests/incremental/01-restart/05-local-wpoint.c similarity index 100% rename from tests/incremental/05-local-wpoint.c rename to tests/incremental/01-restart/05-local-wpoint.c diff --git a/tests/incremental/05-local-wpoint.json b/tests/incremental/01-restart/05-local-wpoint.json similarity index 100% rename from tests/incremental/05-local-wpoint.json rename to tests/incremental/01-restart/05-local-wpoint.json diff --git a/tests/incremental/05-local-wpoint.patch b/tests/incremental/01-restart/05-local-wpoint.patch similarity index 100% rename from tests/incremental/05-local-wpoint.patch rename to tests/incremental/01-restart/05-local-wpoint.patch diff --git a/tests/incremental/06-local-wpoint-read.c b/tests/incremental/01-restart/06-local-wpoint-read.c similarity index 100% rename from tests/incremental/06-local-wpoint-read.c rename to tests/incremental/01-restart/06-local-wpoint-read.c diff --git a/tests/incremental/06-local-wpoint-read.json b/tests/incremental/01-restart/06-local-wpoint-read.json similarity index 100% rename from tests/incremental/06-local-wpoint-read.json rename to tests/incremental/01-restart/06-local-wpoint-read.json diff --git a/tests/incremental/06-local-wpoint-read.patch b/tests/incremental/01-restart/06-local-wpoint-read.patch similarity index 100% rename from tests/incremental/06-local-wpoint-read.patch rename to tests/incremental/01-restart/06-local-wpoint-read.patch diff --git a/tests/incremental/07-hashcons.c b/tests/incremental/01-restart/07-hashcons.c similarity index 100% rename from tests/incremental/07-hashcons.c rename to tests/incremental/01-restart/07-hashcons.c diff --git a/tests/incremental/07-hashcons.json b/tests/incremental/01-restart/07-hashcons.json similarity index 100% rename from tests/incremental/07-hashcons.json rename to tests/incremental/01-restart/07-hashcons.json diff --git a/tests/incremental/07-hashcons.patch b/tests/incremental/01-restart/07-hashcons.patch similarity index 100% rename from tests/incremental/07-hashcons.patch rename to tests/incremental/01-restart/07-hashcons.patch diff --git a/tests/incremental/08-side-restart.c b/tests/incremental/01-restart/08-side-restart.c similarity index 100% rename from tests/incremental/08-side-restart.c rename to tests/incremental/01-restart/08-side-restart.c diff --git a/tests/incremental/08-side-restart.json b/tests/incremental/01-restart/08-side-restart.json similarity index 100% rename from tests/incremental/08-side-restart.json rename to tests/incremental/01-restart/08-side-restart.json diff --git a/tests/incremental/08-side-restart.patch b/tests/incremental/01-restart/08-side-restart.patch similarity index 100% rename from tests/incremental/08-side-restart.patch rename to tests/incremental/01-restart/08-side-restart.patch diff --git a/tests/incremental/06-call-remove.c b/tests/incremental/01-restart/09-call-remove.c similarity index 100% rename from tests/incremental/06-call-remove.c rename to tests/incremental/01-restart/09-call-remove.c diff --git a/tests/incremental/06-call-remove.json b/tests/incremental/01-restart/09-call-remove.json similarity index 100% rename from tests/incremental/06-call-remove.json rename to tests/incremental/01-restart/09-call-remove.json diff --git a/tests/incremental/06-call-remove.patch b/tests/incremental/01-restart/09-call-remove.patch similarity index 100% rename from tests/incremental/06-call-remove.patch rename to tests/incremental/01-restart/09-call-remove.patch diff --git a/tests/incremental/05-paper-example.c b/tests/incremental/01-restart/11-paper-example.c similarity index 100% rename from tests/incremental/05-paper-example.c rename to tests/incremental/01-restart/11-paper-example.c diff --git a/tests/incremental/05-paper-example.json b/tests/incremental/01-restart/11-paper-example.json similarity index 100% rename from tests/incremental/05-paper-example.json rename to tests/incremental/01-restart/11-paper-example.json diff --git a/tests/incremental/05-paper-example.patch b/tests/incremental/01-restart/11-paper-example.patch similarity index 100% rename from tests/incremental/05-paper-example.patch rename to tests/incremental/01-restart/11-paper-example.patch diff --git a/tests/incremental/48-local-wpoint-funcall.c b/tests/incremental/01-restart/48-local-wpoint-funcall.c similarity index 100% rename from tests/incremental/48-local-wpoint-funcall.c rename to tests/incremental/01-restart/48-local-wpoint-funcall.c diff --git a/tests/incremental/48-local-wpoint-funcall.json b/tests/incremental/01-restart/48-local-wpoint-funcall.json similarity index 100% rename from tests/incremental/48-local-wpoint-funcall.json rename to tests/incremental/01-restart/48-local-wpoint-funcall.json diff --git a/tests/incremental/48-local-wpoint-funcall.patch b/tests/incremental/01-restart/48-local-wpoint-funcall.patch similarity index 100% rename from tests/incremental/48-local-wpoint-funcall.patch rename to tests/incremental/01-restart/48-local-wpoint-funcall.patch From e38c303cb1cbfeb1b0bc0444a92909abb1a53044 Mon Sep 17 00:00:00 2001 From: Vesal Vojdani Date: Thu, 16 Dec 2021 20:14:52 +0200 Subject: [PATCH 137/402] Add a space to supress patch warnings. --- tests/incremental/01-restart/01-global-nochange.patch | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/tests/incremental/01-restart/01-global-nochange.patch b/tests/incremental/01-restart/01-global-nochange.patch index 8b13789179..3e6b6117ee 100644 --- a/tests/incremental/01-restart/01-global-nochange.patch +++ b/tests/incremental/01-restart/01-global-nochange.patch @@ -1 +1,10 @@ +diff --git a/tests/incremental/01-restart/01-global-nochange.c b/tests/incremental/01-restart/01-global-nochange.c +@@ -2,7 +2,7 @@ + #include + int g = 1; +- ++// cmt + void* t_fun(void *arg) { + g = 2; + return NULL; From 2a124c3b54c8700935dca36e74d2c4134883a52d Mon Sep 17 00:00:00 2001 From: Vesal Vojdani Date: Thu, 16 Dec 2021 20:39:57 +0200 Subject: [PATCH 138/402] Hack around current script limitation: add todos and whitespace to patches. --- tests/incremental/01-restart/01-global-nochange.c | 6 +++--- tests/incremental/01-restart/02-global-remove.c | 2 +- tests/incremental/01-restart/02-global-remove.patch | 9 ++++----- tests/incremental/01-restart/03-global-change.c | 6 +++--- tests/incremental/01-restart/04-global-add.c | 2 +- tests/incremental/01-restart/05-local-wpoint.c | 2 +- tests/incremental/01-restart/05-local-wpoint.patch | 6 +++--- tests/incremental/01-restart/06-local-wpoint-read.c | 2 +- tests/incremental/01-restart/06-local-wpoint-read.patch | 6 +++--- tests/incremental/01-restart/08-side-restart.c | 4 ++-- tests/incremental/01-restart/08-side-restart.patch | 6 +++--- tests/incremental/01-restart/09-call-remove.c | 2 +- tests/incremental/01-restart/11-paper-example.c | 2 +- tests/incremental/01-restart/48-local-wpoint-funcall.c | 4 ++-- 14 files changed, 29 insertions(+), 30 deletions(-) diff --git a/tests/incremental/01-restart/01-global-nochange.c b/tests/incremental/01-restart/01-global-nochange.c index 5590fe59fb..be8626a4ec 100644 --- a/tests/incremental/01-restart/01-global-nochange.c +++ b/tests/incremental/01-restart/01-global-nochange.c @@ -12,8 +12,8 @@ int main() { pthread_t id; pthread_create(&id, NULL, t_fun, NULL); // just go multithreaded - assert(g == 1); // unknown before and after - assert(g == 2); // unknown before and after - assert(g == 0); // fail before and after + assert(g == 1); // UNKNOWN before and after + assert(g == 2); // UNKNOWN before and after + assert(g == 0); // FAIL before and after return 0; } \ No newline at end of file diff --git a/tests/incremental/01-restart/02-global-remove.c b/tests/incremental/01-restart/02-global-remove.c index baa4706154..b5ab991b82 100644 --- a/tests/incremental/01-restart/02-global-remove.c +++ b/tests/incremental/01-restart/02-global-remove.c @@ -12,6 +12,6 @@ int main() { pthread_t id; pthread_create(&id, NULL, t_fun, NULL); // just go multithreaded - assert(g == 1); // unknown before, success after + assert(g == 1); // TODO (unknown before, success after) return 0; } \ No newline at end of file diff --git a/tests/incremental/01-restart/02-global-remove.patch b/tests/incremental/01-restart/02-global-remove.patch index 2f3c81079d..ae1372a172 100644 --- a/tests/incremental/01-restart/02-global-remove.patch +++ b/tests/incremental/01-restart/02-global-remove.patch @@ -1,10 +1,9 @@ ---- tests/incremental/02-global-remove.c 2021-09-29 14:05:58.951606435 +0300 -+++ "tests/incremental/02-global-remove copy.c" 2021-09-29 14:06:08.619662600 +0300 -@@ -4,7 +4,6 @@ +diff --git a/tests/incremental/01-restart/02-global-remove.c b/tests/incremental/01-restart/02-global-remove.c +@@ -4,7 +4,7 @@ int g = 1; - + void* t_fun(void *arg) { - g = 2; ++ return NULL; } - diff --git a/tests/incremental/01-restart/03-global-change.c b/tests/incremental/01-restart/03-global-change.c index 9d63c62b86..50dea607a1 100644 --- a/tests/incremental/01-restart/03-global-change.c +++ b/tests/incremental/01-restart/03-global-change.c @@ -12,8 +12,8 @@ int main() { pthread_t id; pthread_create(&id, NULL, t_fun, NULL); // just go multithreaded - assert(g == 1); // unknown before, unknown after - assert(g == 2); // unknown before, fail after - assert(g == 0); // fail before, unknown after + assert(g == 1); // UNKNOWN unknown before, unknown after + assert(g == 2); // TODO unknown before, fail after + assert(g == 0); // TODO fail before, unknown after return 0; } \ No newline at end of file diff --git a/tests/incremental/01-restart/04-global-add.c b/tests/incremental/01-restart/04-global-add.c index fa7055149a..aff8254e4b 100644 --- a/tests/incremental/01-restart/04-global-add.c +++ b/tests/incremental/01-restart/04-global-add.c @@ -11,6 +11,6 @@ int main() { pthread_t id; pthread_create(&id, NULL, t_fun, NULL); // just go multithreaded - assert(g == 1); // success before, unknown after + assert(g == 1); // TODO success before, unknown after return 0; } \ No newline at end of file diff --git a/tests/incremental/01-restart/05-local-wpoint.c b/tests/incremental/01-restart/05-local-wpoint.c index cdd9c48541..ac5f8c3a7c 100644 --- a/tests/incremental/01-restart/05-local-wpoint.c +++ b/tests/incremental/01-restart/05-local-wpoint.c @@ -15,7 +15,7 @@ int main() { int x; x = g; while (1) { - assert(x == 1); // unknown before, success after + assert(x == 1); // TODO unknown before, success after x = g; } diff --git a/tests/incremental/01-restart/05-local-wpoint.patch b/tests/incremental/01-restart/05-local-wpoint.patch index 2342e07535..d5ff897203 100644 --- a/tests/incremental/01-restart/05-local-wpoint.patch +++ b/tests/incremental/01-restart/05-local-wpoint.patch @@ -1,10 +1,10 @@ --- tests/incremental/05-local-wpoint.c 2021-09-29 16:30:17.199899879 +0300 +++ "tests/incremental/05-local-wpoint copy.c" 2021-09-29 16:30:30.231977751 +0300 -@@ -4,7 +4,6 @@ +@@ -4,7 +4,7 @@ int g = 1; - + void* t_fun(void *arg) { - g = 0; ++ return NULL; } - diff --git a/tests/incremental/01-restart/06-local-wpoint-read.c b/tests/incremental/01-restart/06-local-wpoint-read.c index d6900bd3a5..c5c2860b1d 100644 --- a/tests/incremental/01-restart/06-local-wpoint-read.c +++ b/tests/incremental/01-restart/06-local-wpoint-read.c @@ -16,7 +16,7 @@ int main() { x = g; while (1) { g = x; - assert(x == 1); // unknown before, success after + assert(x == 1); // TODO unknown before, success after x = g; } diff --git a/tests/incremental/01-restart/06-local-wpoint-read.patch b/tests/incremental/01-restart/06-local-wpoint-read.patch index 1767552a45..9b4a616f8a 100644 --- a/tests/incremental/01-restart/06-local-wpoint-read.patch +++ b/tests/incremental/01-restart/06-local-wpoint-read.patch @@ -1,10 +1,10 @@ --- tests/incremental/06-local-wpoint-read.c 2021-09-29 16:55:20.461556453 +0300 +++ "tests/incremental/06-local-wpoint-read copy.c" 2021-09-29 16:55:51.013749361 +0300 -@@ -4,7 +4,6 @@ +@@ -4,7 +4,7 @@ int g = 1; - + void* t_fun(void *arg) { - g = 0; ++ return NULL; } - diff --git a/tests/incremental/01-restart/08-side-restart.c b/tests/incremental/01-restart/08-side-restart.c index cdab5d408f..dde8d8f15b 100644 --- a/tests/incremental/01-restart/08-side-restart.c +++ b/tests/incremental/01-restart/08-side-restart.c @@ -5,7 +5,7 @@ int g; void* t_fun1(void *arg) { int x = g; - assert(x <= 8); + assert(x <= 8); // TODO return NULL; } @@ -17,7 +17,7 @@ void* t_fun2(void *arg) { int main() { pthread_t id1, id2; pthread_create(&id1, NULL, t_fun1, NULL); - + int i = 0; int j; diff --git a/tests/incremental/01-restart/08-side-restart.patch b/tests/incremental/01-restart/08-side-restart.patch index bc3607d94a..87b605cde4 100644 --- a/tests/incremental/01-restart/08-side-restart.patch +++ b/tests/incremental/01-restart/08-side-restart.patch @@ -1,10 +1,10 @@ --- a/tests/incremental/08-side-restart.c +++ b/tests/incremental/08-side-restart.c -@@ -10,7 +10,6 @@ void* t_fun1(void *arg) { +@@ -10,7 +10,7 @@ void* t_fun1(void *arg) { } - + void* t_fun2(void *arg) { - g = 0; ++ return NULL; } - diff --git a/tests/incremental/01-restart/09-call-remove.c b/tests/incremental/01-restart/09-call-remove.c index 87aec95350..7cc28b450c 100644 --- a/tests/incremental/01-restart/09-call-remove.c +++ b/tests/incremental/01-restart/09-call-remove.c @@ -13,7 +13,7 @@ void* t_fun(void *arg) { } void* t_fun2(void *arg) { - assert(g == 1); // unknown before, success after + assert(g == 1); // TODO unknown before, success after return NULL; } diff --git a/tests/incremental/01-restart/11-paper-example.c b/tests/incremental/01-restart/11-paper-example.c index 735728db07..76a822286a 100644 --- a/tests/incremental/01-restart/11-paper-example.c +++ b/tests/incremental/01-restart/11-paper-example.c @@ -20,7 +20,7 @@ void* consumer(void *arg) { res = fp(); } pthread_mutex_unlock(&mutex); - assert(res >= 0); + assert(res >= 0); // TODO success after res = 0; // change absorbed return NULL; diff --git a/tests/incremental/01-restart/48-local-wpoint-funcall.c b/tests/incremental/01-restart/48-local-wpoint-funcall.c index 123a86004e..40b8a745b5 100644 --- a/tests/incremental/01-restart/48-local-wpoint-funcall.c +++ b/tests/incremental/01-restart/48-local-wpoint-funcall.c @@ -10,9 +10,9 @@ int main() { while (x < 10) { y = f(x); x = x + y; - assert(x == 0); + assert(x == 0); // TODO (fail before, success after?) } - assert(0); + assert(0); // TODO (fail before, nothing after) return 0; } \ No newline at end of file From 42afac5ab2542010a8f3fd8695edbcf859525560 Mon Sep 17 00:00:00 2001 From: Vesal Vojdani Date: Thu, 16 Dec 2021 21:25:59 +0200 Subject: [PATCH 139/402] Before/after using the patches. --- .../incremental/01-restart/02-global-remove.c | 2 +- .../01-restart/02-global-remove.patch | 10 ++++++++ .../incremental/01-restart/03-global-change.c | 6 ++--- .../01-restart/03-global-change.patch | 17 ++++++++++++-- tests/incremental/01-restart/04-global-add.c | 3 ++- .../01-restart/04-global-add.patch | 18 ++++++++++++--- .../incremental/01-restart/05-local-wpoint.c | 2 +- .../01-restart/05-local-wpoint.patch | 9 ++++++++ .../01-restart/06-local-wpoint-read.c | 2 +- .../01-restart/06-local-wpoint-read.patch | 9 ++++++++ tests/incremental/01-restart/09-call-remove.c | 2 +- .../01-restart/09-call-remove.patch | 12 ++++++++-- .../incremental/01-restart/11-paper-example.c | 2 +- .../01-restart/11-paper-example.patch | 23 +++++++++++++++---- .../01-restart/48-local-wpoint-funcall.c | 4 ++-- .../01-restart/48-local-wpoint-funcall.patch | 18 +++++++++++++-- 16 files changed, 115 insertions(+), 24 deletions(-) diff --git a/tests/incremental/01-restart/02-global-remove.c b/tests/incremental/01-restart/02-global-remove.c index b5ab991b82..4763016e7c 100644 --- a/tests/incremental/01-restart/02-global-remove.c +++ b/tests/incremental/01-restart/02-global-remove.c @@ -12,6 +12,6 @@ int main() { pthread_t id; pthread_create(&id, NULL, t_fun, NULL); // just go multithreaded - assert(g == 1); // TODO (unknown before, success after) + assert(g == 1); // UNKNOWN before, success after return 0; } \ No newline at end of file diff --git a/tests/incremental/01-restart/02-global-remove.patch b/tests/incremental/01-restart/02-global-remove.patch index ae1372a172..a80934c41d 100644 --- a/tests/incremental/01-restart/02-global-remove.patch +++ b/tests/incremental/01-restart/02-global-remove.patch @@ -7,3 +7,13 @@ diff --git a/tests/incremental/01-restart/02-global-remove.c b/tests/incremental + return NULL; } + +@@ -12,6 +12,6 @@ int main() { + pthread_t id; + pthread_create(&id, NULL, t_fun, NULL); // just go multithreaded + +- assert(g == 1); // UNKNOWN before, success after ++ assert(g == 1); // unknown before, SUCCESS after + return 0; + } +\ No newline at end of file diff --git a/tests/incremental/01-restart/03-global-change.c b/tests/incremental/01-restart/03-global-change.c index 50dea607a1..59d1a37a5a 100644 --- a/tests/incremental/01-restart/03-global-change.c +++ b/tests/incremental/01-restart/03-global-change.c @@ -12,8 +12,8 @@ int main() { pthread_t id; pthread_create(&id, NULL, t_fun, NULL); // just go multithreaded - assert(g == 1); // UNKNOWN unknown before, unknown after - assert(g == 2); // TODO unknown before, fail after - assert(g == 0); // TODO fail before, unknown after + assert(g == 1); // UNKNOWN before, unknown after + assert(g == 2); // UNKNOWN before, fail after + assert(g == 0); // FAIL before, unknown after return 0; } \ No newline at end of file diff --git a/tests/incremental/01-restart/03-global-change.patch b/tests/incremental/01-restart/03-global-change.patch index db7d935591..be67039535 100644 --- a/tests/incremental/01-restart/03-global-change.patch +++ b/tests/incremental/01-restart/03-global-change.patch @@ -2,10 +2,23 @@ +++ "tests/incremental/03-global-change copy.c" 2021-09-29 14:09:11.456724953 +0300 @@ -4,7 +4,7 @@ int g = 1; - + void* t_fun(void *arg) { - g = 2; + g = 0; return NULL; } - + +@@ -12,8 +12,8 @@ int main() { + pthread_t id; + pthread_create(&id, NULL, t_fun, NULL); // just go multithreaded + +- assert(g == 1); // UNKNOWN before, unknown after +- assert(g == 2); // UNKNOWN before, fail after +- assert(g == 0); // FAIL before, unknown after ++ assert(g == 1); // unknown before, UNKNOWN after ++ assert(g == 2); // unknown before, FAIL after ++ assert(g == 0); // fail before, UNKNOWN after + return 0; + } +\ No newline at end of file diff --git a/tests/incremental/01-restart/04-global-add.c b/tests/incremental/01-restart/04-global-add.c index aff8254e4b..312987db65 100644 --- a/tests/incremental/01-restart/04-global-add.c +++ b/tests/incremental/01-restart/04-global-add.c @@ -4,6 +4,7 @@ int g = 1; void* t_fun(void *arg) { + return NULL; } @@ -11,6 +12,6 @@ int main() { pthread_t id; pthread_create(&id, NULL, t_fun, NULL); // just go multithreaded - assert(g == 1); // TODO success before, unknown after + assert(g == 1); // SUCCESS before, unknown after return 0; } \ No newline at end of file diff --git a/tests/incremental/01-restart/04-global-add.patch b/tests/incremental/01-restart/04-global-add.patch index 499603b716..88e2e7715b 100644 --- a/tests/incremental/01-restart/04-global-add.patch +++ b/tests/incremental/01-restart/04-global-add.patch @@ -1,10 +1,22 @@ ---- tests/incremental/04-global-add.c 2021-09-29 14:11:10.085414395 +0300 -+++ "tests/incremental/04-global-add copy.c" 2021-09-29 14:11:15.785447525 +0300 -@@ -4,6 +4,7 @@ +diff --git a/tests/incremental/01-restart/04-global-add.c b/tests/incremental/01-restart/04-global-add.c +index 312987db6..f8ddc4bf0 100644 +--- a/tests/incremental/01-restart/04-global-add.c ++++ b/tests/incremental/01-restart/04-global-add.c +@@ -4,7 +4,7 @@ int g = 1; void* t_fun(void *arg) { +- + g = 2; return NULL; } +@@ -12,6 +12,6 @@ int main() { + pthread_t id; + pthread_create(&id, NULL, t_fun, NULL); // just go multithreaded + +- assert(g == 1); // SUCCESS before, unknown after ++ assert(g == 1); // success before, UNKNOWN after + return 0; + } +\ No newline at end of file diff --git a/tests/incremental/01-restart/05-local-wpoint.c b/tests/incremental/01-restart/05-local-wpoint.c index ac5f8c3a7c..c27d799526 100644 --- a/tests/incremental/01-restart/05-local-wpoint.c +++ b/tests/incremental/01-restart/05-local-wpoint.c @@ -15,7 +15,7 @@ int main() { int x; x = g; while (1) { - assert(x == 1); // TODO unknown before, success after + assert(x == 1); // UNKNOWN before, success after x = g; } diff --git a/tests/incremental/01-restart/05-local-wpoint.patch b/tests/incremental/01-restart/05-local-wpoint.patch index d5ff897203..8b6fdeb587 100644 --- a/tests/incremental/01-restart/05-local-wpoint.patch +++ b/tests/incremental/01-restart/05-local-wpoint.patch @@ -8,3 +8,12 @@ + return NULL; } + +@@ -15,7 +15,7 @@ int main() { + int x; + x = g; + while (1) { +- assert(x == 1); // UNKNOWN before, success after ++ assert(x == 1); // unknown before, SUCCESS after + x = g; + } diff --git a/tests/incremental/01-restart/06-local-wpoint-read.c b/tests/incremental/01-restart/06-local-wpoint-read.c index c5c2860b1d..d46064e83b 100644 --- a/tests/incremental/01-restart/06-local-wpoint-read.c +++ b/tests/incremental/01-restart/06-local-wpoint-read.c @@ -16,7 +16,7 @@ int main() { x = g; while (1) { g = x; - assert(x == 1); // TODO unknown before, success after + assert(x == 1); // UNKNOWN before, success after x = g; } diff --git a/tests/incremental/01-restart/06-local-wpoint-read.patch b/tests/incremental/01-restart/06-local-wpoint-read.patch index 9b4a616f8a..dfa092d5cc 100644 --- a/tests/incremental/01-restart/06-local-wpoint-read.patch +++ b/tests/incremental/01-restart/06-local-wpoint-read.patch @@ -8,3 +8,12 @@ + return NULL; } + +@@ -16,7 +16,7 @@ int main() { + x = g; + while (1) { + g = x; +- assert(x == 1); // UNKNOWN before, success after ++ assert(x == 1); // unknown before, SUCCESS after + x = g; + } diff --git a/tests/incremental/01-restart/09-call-remove.c b/tests/incremental/01-restart/09-call-remove.c index 7cc28b450c..bff636c6bb 100644 --- a/tests/incremental/01-restart/09-call-remove.c +++ b/tests/incremental/01-restart/09-call-remove.c @@ -13,7 +13,7 @@ void* t_fun(void *arg) { } void* t_fun2(void *arg) { - assert(g == 1); // TODO unknown before, success after + assert(g == 1); // UNKNOWN before, success after return NULL; } diff --git a/tests/incremental/01-restart/09-call-remove.patch b/tests/incremental/01-restart/09-call-remove.patch index 8c96c9d0c6..022014b9b3 100644 --- a/tests/incremental/01-restart/09-call-remove.patch +++ b/tests/incremental/01-restart/09-call-remove.patch @@ -2,10 +2,18 @@ +++ "tests/incremental/06-call-remove copy.c" 2021-10-05 10:49:37.397808651 +0300 @@ -8,7 +8,7 @@ } - + void* t_fun(void *arg) { - foo(); + // foo(); return NULL; } - + +@@ -13,7 +13,7 @@ void* t_fun(void *arg) { + } + + void* t_fun2(void *arg) { +- assert(g == 1); // UNKNOWN before, success after ++ assert(g == 1); // unknown before, SUCCESS after + return NULL; + } \ No newline at end of file diff --git a/tests/incremental/01-restart/11-paper-example.c b/tests/incremental/01-restart/11-paper-example.c index 76a822286a..1b1f385724 100644 --- a/tests/incremental/01-restart/11-paper-example.c +++ b/tests/incremental/01-restart/11-paper-example.c @@ -20,7 +20,7 @@ void* consumer(void *arg) { res = fp(); } pthread_mutex_unlock(&mutex); - assert(res >= 0); // TODO success after + assert(res >= 0); // UNKNOWN before, success after res = 0; // change absorbed return NULL; diff --git a/tests/incremental/01-restart/11-paper-example.patch b/tests/incremental/01-restart/11-paper-example.patch index 21c08b5911..8157b2b0b6 100644 --- a/tests/incremental/01-restart/11-paper-example.patch +++ b/tests/incremental/01-restart/11-paper-example.patch @@ -1,4 +1,19 @@ -32c32 -< fp = bad; ---- -> fp = good; +diff --git a/tests/incremental/01-restart/11-paper-example.c b/tests/incremental/01-restart/11-paper-example.c +@@ -20,7 +20,7 @@ void* consumer(void *arg) { + res = fp(); + } + pthread_mutex_unlock(&mutex); +- assert(res >= 0); // UNKNOWN before, success after ++ assert(res >= 0); // unknown before, SUCCESS after + res = 0; + // change absorbed + return NULL; +@@ -29,7 +29,7 @@ void* consumer(void *arg) { + void* producer(void *arg) { + int res = 0; + pthread_mutex_lock(&mutex); +- fp = bad; ++ fp = good; + pthread_mutex_unlock(&mutex); + return NULL; + } diff --git a/tests/incremental/01-restart/48-local-wpoint-funcall.c b/tests/incremental/01-restart/48-local-wpoint-funcall.c index 40b8a745b5..410ff7cccb 100644 --- a/tests/incremental/01-restart/48-local-wpoint-funcall.c +++ b/tests/incremental/01-restart/48-local-wpoint-funcall.c @@ -10,9 +10,9 @@ int main() { while (x < 10) { y = f(x); x = x + y; - assert(x == 0); // TODO (fail before, success after?) + assert(x == 0); // FAIL before, success after } - assert(0); // TODO (fail before, nothing after) + assert(0); // FAIL before, nothing after return 0; } \ No newline at end of file diff --git a/tests/incremental/01-restart/48-local-wpoint-funcall.patch b/tests/incremental/01-restart/48-local-wpoint-funcall.patch index 87b48792c0..b5441cf3fd 100644 --- a/tests/incremental/01-restart/48-local-wpoint-funcall.patch +++ b/tests/incremental/01-restart/48-local-wpoint-funcall.patch @@ -4,10 +4,24 @@ index 1de02a51b..bdcb2875f 100644 +++ b/tests/incremental/48-local-wpoint-funcall.c @@ -1,7 +1,7 @@ #include - + int f(int x) { - return 1; + return 0; } - + int main() { + +@@ -10,9 +10,9 @@ int main() { + while (x < 10) { + y = f(x); + x = x + y; +- assert(x == 0); // FAIL before, success after ++ assert(x == 0); // fail before, SUCCESS after + } + +- assert(0); // FAIL before, nothing after ++ assert(0); // fail before, NOWARN after + return 0; + } +\ No newline at end of file \ No newline at end of file From 17bb3bc963956033a57d055cdbcb3d755f52fa18 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Tue, 21 Dec 2021 12:30:30 +0200 Subject: [PATCH 140/402] Fix fixpoint with incremental abort in 02-abort/02-abort-smtprc During incremental.save rho was pruned from unreachable context, but infl, side_infl and side_dep remained. This caused spurious destab_dep values (and hence abort) for variables not in rho (so bot). --- src/solvers/td3.ml | 15 ++++++++++++++- tests/incremental/02-abort/02-abort-smtprc.c | 1 - 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/src/solvers/td3.ml b/src/solvers/td3.ml index a2fb1ef133..4e162ca713 100644 --- a/src/solvers/td3.ml +++ b/src/solvers/td3.ml @@ -824,7 +824,20 @@ module WP = let finalize ~vh ~reachable = VH.filteri_inplace (fun x _ -> VH.mem reachable x - ) stable + ) stable; + + (* filter both keys and value sets of a VS.t HM.t *) + let filter_vs_hm hm = + VH.filter_map_inplace (fun x vs -> + if VH.mem reachable x then + Some (VS.filter (VH.mem reachable) vs) + else + None + ) hm + in + filter_vs_hm infl; + filter_vs_hm side_infl; + filter_vs_hm side_dep; (* TODO: prune other data structures? *) end in diff --git a/tests/incremental/02-abort/02-abort-smtprc.c b/tests/incremental/02-abort/02-abort-smtprc.c index e6c011c2ee..8c1eee4275 100644 --- a/tests/incremental/02-abort/02-abort-smtprc.c +++ b/tests/incremental/02-abort/02-abort-smtprc.c @@ -1,4 +1,3 @@ -// SKIP struct { unsigned a; } b; From 2fac1b809962c55dab6e4ee2d372feef86ce3406 Mon Sep 17 00:00:00 2001 From: Vesal Vojdani Date: Wed, 22 Dec 2021 14:59:41 +0200 Subject: [PATCH 141/402] Add stupid script to fix patch headers after moves. --- scripts/fix_patch_headers.sh | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100755 scripts/fix_patch_headers.sh diff --git a/scripts/fix_patch_headers.sh b/scripts/fix_patch_headers.sh new file mode 100755 index 0000000000..f20941e62b --- /dev/null +++ b/scripts/fix_patch_headers.sh @@ -0,0 +1,8 @@ +#!/bin/bash +#Run from root, e.g.,: ./scripts/fix_patch_headers.sh tests/incremental/11-restart/*.patch +for file in "$@" +do + efile="${file//\//\\/}" + echo "$file" + perl -0777 -i -pe "s/.*?@/--- a\/$efile\n+++ b\/$efile\n@/is" $file +done From 399c6a2bf386b61e2cbf51277e123ade657b3dae Mon Sep 17 00:00:00 2001 From: Vesal Vojdani Date: Wed, 22 Dec 2021 15:28:43 +0200 Subject: [PATCH 142/402] Fix file extension for patch headings. --- scripts/fix_patch_headers.sh | 5 +++-- tests/incremental/11-restart/00-justglob.patch | 4 ++-- tests/incremental/11-restart/01-global-nochange.patch | 4 ++-- tests/incremental/11-restart/02-global-remove.patch | 4 ++-- tests/incremental/11-restart/03-global-change.patch | 4 ++-- tests/incremental/11-restart/04-global-add.patch | 4 ++-- tests/incremental/11-restart/05-local-wpoint.patch | 4 ++-- tests/incremental/11-restart/06-local-wpoint-read.patch | 4 ++-- tests/incremental/11-restart/08-side-restart.patch | 4 ++-- tests/incremental/11-restart/09-call-remove.patch | 4 ++-- tests/incremental/11-restart/11-paper-example.patch | 4 ++-- tests/incremental/11-restart/48-local-wpoint-funcall.patch | 4 ++-- tests/incremental/12-abort/01-abort_aget.patch | 4 ++-- tests/incremental/12-abort/02-abort-smtprc.patch | 4 ++-- 14 files changed, 29 insertions(+), 28 deletions(-) diff --git a/scripts/fix_patch_headers.sh b/scripts/fix_patch_headers.sh index f20941e62b..db9525a83c 100755 --- a/scripts/fix_patch_headers.sh +++ b/scripts/fix_patch_headers.sh @@ -2,7 +2,8 @@ #Run from root, e.g.,: ./scripts/fix_patch_headers.sh tests/incremental/11-restart/*.patch for file in "$@" do - efile="${file//\//\\/}" - echo "$file" + echo $file + cfile="${file%.patch}.c" + efile="${cfile//\//\\/}" perl -0777 -i -pe "s/.*?@/--- a\/$efile\n+++ b\/$efile\n@/is" $file done diff --git a/tests/incremental/11-restart/00-justglob.patch b/tests/incremental/11-restart/00-justglob.patch index ef078a4822..2966496927 100644 --- a/tests/incremental/11-restart/00-justglob.patch +++ b/tests/incremental/11-restart/00-justglob.patch @@ -1,5 +1,5 @@ ---- a/tests/incremental/11-restart/00-justglob.patch -+++ b/tests/incremental/11-restart/00-justglob.patch +--- a/tests/incremental/11-restart/00-justglob.c ++++ b/tests/incremental/11-restart/00-justglob.c @@ -1,2 +1,2 @@ -int max_domains = 0; +int max_domains = 4; diff --git a/tests/incremental/11-restart/01-global-nochange.patch b/tests/incremental/11-restart/01-global-nochange.patch index f804cd8bbe..cee2794433 100644 --- a/tests/incremental/11-restart/01-global-nochange.patch +++ b/tests/incremental/11-restart/01-global-nochange.patch @@ -1,5 +1,5 @@ ---- a/tests/incremental/11-restart/01-global-nochange.patch -+++ b/tests/incremental/11-restart/01-global-nochange.patch +--- a/tests/incremental/11-restart/01-global-nochange.c ++++ b/tests/incremental/11-restart/01-global-nochange.c @@ -2,7 +2,7 @@ #include diff --git a/tests/incremental/11-restart/02-global-remove.patch b/tests/incremental/11-restart/02-global-remove.patch index 3913057d40..11e947a376 100644 --- a/tests/incremental/11-restart/02-global-remove.patch +++ b/tests/incremental/11-restart/02-global-remove.patch @@ -1,5 +1,5 @@ ---- a/tests/incremental/11-restart/02-global-remove.patch -+++ b/tests/incremental/11-restart/02-global-remove.patch +--- a/tests/incremental/11-restart/02-global-remove.c ++++ b/tests/incremental/11-restart/02-global-remove.c @@ -4,7 +4,7 @@ int g = 1; diff --git a/tests/incremental/11-restart/03-global-change.patch b/tests/incremental/11-restart/03-global-change.patch index 91d1887bda..9ab527aaef 100644 --- a/tests/incremental/11-restart/03-global-change.patch +++ b/tests/incremental/11-restart/03-global-change.patch @@ -1,5 +1,5 @@ ---- a/tests/incremental/11-restart/03-global-change.patch -+++ b/tests/incremental/11-restart/03-global-change.patch +--- a/tests/incremental/11-restart/03-global-change.c ++++ b/tests/incremental/11-restart/03-global-change.c @@ -4,7 +4,7 @@ int g = 1; diff --git a/tests/incremental/11-restart/04-global-add.patch b/tests/incremental/11-restart/04-global-add.patch index 6c1b8c5882..fdc476ac6f 100644 --- a/tests/incremental/11-restart/04-global-add.patch +++ b/tests/incremental/11-restart/04-global-add.patch @@ -1,5 +1,5 @@ ---- a/tests/incremental/11-restart/04-global-add.patch -+++ b/tests/incremental/11-restart/04-global-add.patch +--- a/tests/incremental/11-restart/04-global-add.c ++++ b/tests/incremental/11-restart/04-global-add.c @@ -4,7 +4,7 @@ int g = 1; diff --git a/tests/incremental/11-restart/05-local-wpoint.patch b/tests/incremental/11-restart/05-local-wpoint.patch index 58f3710bcd..1e28de5328 100644 --- a/tests/incremental/11-restart/05-local-wpoint.patch +++ b/tests/incremental/11-restart/05-local-wpoint.patch @@ -1,5 +1,5 @@ ---- a/tests/incremental/11-restart/05-local-wpoint.patch -+++ b/tests/incremental/11-restart/05-local-wpoint.patch +--- a/tests/incremental/11-restart/05-local-wpoint.c ++++ b/tests/incremental/11-restart/05-local-wpoint.c @@ -4,7 +4,7 @@ int g = 1; diff --git a/tests/incremental/11-restart/06-local-wpoint-read.patch b/tests/incremental/11-restart/06-local-wpoint-read.patch index 59fe7a6ad1..a76a4889f9 100644 --- a/tests/incremental/11-restart/06-local-wpoint-read.patch +++ b/tests/incremental/11-restart/06-local-wpoint-read.patch @@ -1,5 +1,5 @@ ---- a/tests/incremental/11-restart/06-local-wpoint-read.patch -+++ b/tests/incremental/11-restart/06-local-wpoint-read.patch +--- a/tests/incremental/11-restart/06-local-wpoint-read.c ++++ b/tests/incremental/11-restart/06-local-wpoint-read.c @@ -4,7 +4,7 @@ int g = 1; diff --git a/tests/incremental/11-restart/08-side-restart.patch b/tests/incremental/11-restart/08-side-restart.patch index 7d0461d7ec..ac0f452676 100644 --- a/tests/incremental/11-restart/08-side-restart.patch +++ b/tests/incremental/11-restart/08-side-restart.patch @@ -1,5 +1,5 @@ ---- a/tests/incremental/11-restart/08-side-restart.patch -+++ b/tests/incremental/11-restart/08-side-restart.patch +--- a/tests/incremental/11-restart/08-side-restart.c ++++ b/tests/incremental/11-restart/08-side-restart.c @@ -10,7 +10,7 @@ void* t_fun1(void *arg) { } diff --git a/tests/incremental/11-restart/09-call-remove.patch b/tests/incremental/11-restart/09-call-remove.patch index b65c313c53..d08eff7eaf 100644 --- a/tests/incremental/11-restart/09-call-remove.patch +++ b/tests/incremental/11-restart/09-call-remove.patch @@ -1,5 +1,5 @@ ---- a/tests/incremental/11-restart/09-call-remove.patch -+++ b/tests/incremental/11-restart/09-call-remove.patch +--- a/tests/incremental/11-restart/09-call-remove.c ++++ b/tests/incremental/11-restart/09-call-remove.c @@ -8,7 +8,7 @@ } diff --git a/tests/incremental/11-restart/11-paper-example.patch b/tests/incremental/11-restart/11-paper-example.patch index f004c08d60..fb15f57679 100644 --- a/tests/incremental/11-restart/11-paper-example.patch +++ b/tests/incremental/11-restart/11-paper-example.patch @@ -1,5 +1,5 @@ ---- a/tests/incremental/11-restart/11-paper-example.patch -+++ b/tests/incremental/11-restart/11-paper-example.patch +--- a/tests/incremental/11-restart/11-paper-example.c ++++ b/tests/incremental/11-restart/11-paper-example.c @@ -20,7 +20,7 @@ void* consumer(void *arg) { res = fp(); } diff --git a/tests/incremental/11-restart/48-local-wpoint-funcall.patch b/tests/incremental/11-restart/48-local-wpoint-funcall.patch index 84a2639be3..34d33acb08 100644 --- a/tests/incremental/11-restart/48-local-wpoint-funcall.patch +++ b/tests/incremental/11-restart/48-local-wpoint-funcall.patch @@ -1,5 +1,5 @@ ---- a/tests/incremental/11-restart/48-local-wpoint-funcall.patch -+++ b/tests/incremental/11-restart/48-local-wpoint-funcall.patch +--- a/tests/incremental/11-restart/48-local-wpoint-funcall.c ++++ b/tests/incremental/11-restart/48-local-wpoint-funcall.c @@ -1,7 +1,7 @@ #include diff --git a/tests/incremental/12-abort/01-abort_aget.patch b/tests/incremental/12-abort/01-abort_aget.patch index 99a1721d23..657688e79f 100644 --- a/tests/incremental/12-abort/01-abort_aget.patch +++ b/tests/incremental/12-abort/01-abort_aget.patch @@ -1,5 +1,5 @@ ---- a/tests/incremental/12-abort/01-abort_aget.patch -+++ b/tests/incremental/12-abort/01-abort_aget.patch +--- a/tests/incremental/12-abort/01-abort_aget.c ++++ b/tests/incremental/12-abort/01-abort_aget.c @@ -4,7 +4,7 @@ void b(); void c() {} diff --git a/tests/incremental/12-abort/02-abort-smtprc.patch b/tests/incremental/12-abort/02-abort-smtprc.patch index 06e8d93383..51110a81ef 100644 --- a/tests/incremental/12-abort/02-abort-smtprc.patch +++ b/tests/incremental/12-abort/02-abort-smtprc.patch @@ -1,5 +1,5 @@ ---- a/tests/incremental/12-abort/02-abort-smtprc.patch -+++ b/tests/incremental/12-abort/02-abort-smtprc.patch +--- a/tests/incremental/12-abort/02-abort-smtprc.c ++++ b/tests/incremental/12-abort/02-abort-smtprc.c @@ -26,7 +26,7 @@ int i(int l) { while (m) { f(l); From 0cc4f0f06f0e131454cf4aeeae2fb79db54520a3 Mon Sep 17 00:00:00 2001 From: Vesal Vojdani Date: Wed, 22 Dec 2021 16:23:05 +0200 Subject: [PATCH 143/402] Finally correct patch format; fix 11/48. --- scripts/fix_patch_headers.sh | 2 +- .../incremental/11-restart/00-justglob.patch | 4 ++-- .../11-restart/01-global-nochange.patch | 4 ++-- .../11-restart/02-global-remove.patch | 4 ++-- .../11-restart/03-global-change.patch | 4 ++-- .../11-restart/04-global-add.patch | 6 ++--- .../11-restart/05-local-wpoint.patch | 4 ++-- .../11-restart/06-local-wpoint-read.patch | 4 ++-- .../11-restart/08-side-restart.patch | 4 ++-- .../11-restart/09-call-remove.patch | 4 ++-- .../11-restart/11-paper-example.patch | 4 ++-- .../11-restart/48-local-wpoint-funcall.c | 2 +- .../11-restart/48-local-wpoint-funcall.json | 22 +++++++++++++------ .../11-restart/48-local-wpoint-funcall.patch | 7 +++--- .../incremental/12-abort/01-abort_aget.patch | 4 ++-- .../12-abort/02-abort-smtprc.patch | 4 ++-- 16 files changed, 45 insertions(+), 38 deletions(-) diff --git a/scripts/fix_patch_headers.sh b/scripts/fix_patch_headers.sh index db9525a83c..b48ca06c0b 100755 --- a/scripts/fix_patch_headers.sh +++ b/scripts/fix_patch_headers.sh @@ -5,5 +5,5 @@ do echo $file cfile="${file%.patch}.c" efile="${cfile//\//\\/}" - perl -0777 -i -pe "s/.*?@/--- a\/$efile\n+++ b\/$efile\n@/is" $file + perl -0777 -i -pe "s/.*?@/--- $efile\n+++ $efile\n@/is" $file done diff --git a/tests/incremental/11-restart/00-justglob.patch b/tests/incremental/11-restart/00-justglob.patch index 2966496927..cc43da4357 100644 --- a/tests/incremental/11-restart/00-justglob.patch +++ b/tests/incremental/11-restart/00-justglob.patch @@ -1,5 +1,5 @@ ---- a/tests/incremental/11-restart/00-justglob.c -+++ b/tests/incremental/11-restart/00-justglob.c +--- tests/incremental/11-restart/00-justglob.c ++++ tests/incremental/11-restart/00-justglob.c @@ -1,2 +1,2 @@ -int max_domains = 0; +int max_domains = 4; diff --git a/tests/incremental/11-restart/01-global-nochange.patch b/tests/incremental/11-restart/01-global-nochange.patch index cee2794433..af96d85502 100644 --- a/tests/incremental/11-restart/01-global-nochange.patch +++ b/tests/incremental/11-restart/01-global-nochange.patch @@ -1,5 +1,5 @@ ---- a/tests/incremental/11-restart/01-global-nochange.c -+++ b/tests/incremental/11-restart/01-global-nochange.c +--- tests/incremental/11-restart/01-global-nochange.c ++++ tests/incremental/11-restart/01-global-nochange.c @@ -2,7 +2,7 @@ #include diff --git a/tests/incremental/11-restart/02-global-remove.patch b/tests/incremental/11-restart/02-global-remove.patch index 11e947a376..afe763d2ee 100644 --- a/tests/incremental/11-restart/02-global-remove.patch +++ b/tests/incremental/11-restart/02-global-remove.patch @@ -1,5 +1,5 @@ ---- a/tests/incremental/11-restart/02-global-remove.c -+++ b/tests/incremental/11-restart/02-global-remove.c +--- tests/incremental/11-restart/02-global-remove.c ++++ tests/incremental/11-restart/02-global-remove.c @@ -4,7 +4,7 @@ int g = 1; diff --git a/tests/incremental/11-restart/03-global-change.patch b/tests/incremental/11-restart/03-global-change.patch index 9ab527aaef..69998c505e 100644 --- a/tests/incremental/11-restart/03-global-change.patch +++ b/tests/incremental/11-restart/03-global-change.patch @@ -1,5 +1,5 @@ ---- a/tests/incremental/11-restart/03-global-change.c -+++ b/tests/incremental/11-restart/03-global-change.c +--- tests/incremental/11-restart/03-global-change.c ++++ tests/incremental/11-restart/03-global-change.c @@ -4,7 +4,7 @@ int g = 1; diff --git a/tests/incremental/11-restart/04-global-add.patch b/tests/incremental/11-restart/04-global-add.patch index fdc476ac6f..8aa80bb000 100644 --- a/tests/incremental/11-restart/04-global-add.patch +++ b/tests/incremental/11-restart/04-global-add.patch @@ -2,17 +2,17 @@ +++ b/tests/incremental/11-restart/04-global-add.c @@ -4,7 +4,7 @@ int g = 1; - + void* t_fun(void *arg) { - + g = 2; return NULL; } - + @@ -12,6 +12,6 @@ int main() { pthread_t id; pthread_create(&id, NULL, t_fun, NULL); // just go multithreaded - + - assert(g == 1); // SUCCESS before, unknown after + assert(g == 1); // success before, UNKNOWN after return 0; diff --git a/tests/incremental/11-restart/05-local-wpoint.patch b/tests/incremental/11-restart/05-local-wpoint.patch index 1e28de5328..b5456d9dbf 100644 --- a/tests/incremental/11-restart/05-local-wpoint.patch +++ b/tests/incremental/11-restart/05-local-wpoint.patch @@ -1,5 +1,5 @@ ---- a/tests/incremental/11-restart/05-local-wpoint.c -+++ b/tests/incremental/11-restart/05-local-wpoint.c +--- tests/incremental/11-restart/05-local-wpoint.c ++++ tests/incremental/11-restart/05-local-wpoint.c @@ -4,7 +4,7 @@ int g = 1; diff --git a/tests/incremental/11-restart/06-local-wpoint-read.patch b/tests/incremental/11-restart/06-local-wpoint-read.patch index a76a4889f9..6d6b407142 100644 --- a/tests/incremental/11-restart/06-local-wpoint-read.patch +++ b/tests/incremental/11-restart/06-local-wpoint-read.patch @@ -1,5 +1,5 @@ ---- a/tests/incremental/11-restart/06-local-wpoint-read.c -+++ b/tests/incremental/11-restart/06-local-wpoint-read.c +--- tests/incremental/11-restart/06-local-wpoint-read.c ++++ tests/incremental/11-restart/06-local-wpoint-read.c @@ -4,7 +4,7 @@ int g = 1; diff --git a/tests/incremental/11-restart/08-side-restart.patch b/tests/incremental/11-restart/08-side-restart.patch index ac0f452676..e3b22d3aca 100644 --- a/tests/incremental/11-restart/08-side-restart.patch +++ b/tests/incremental/11-restart/08-side-restart.patch @@ -1,5 +1,5 @@ ---- a/tests/incremental/11-restart/08-side-restart.c -+++ b/tests/incremental/11-restart/08-side-restart.c +--- tests/incremental/11-restart/08-side-restart.c ++++ tests/incremental/11-restart/08-side-restart.c @@ -10,7 +10,7 @@ void* t_fun1(void *arg) { } diff --git a/tests/incremental/11-restart/09-call-remove.patch b/tests/incremental/11-restart/09-call-remove.patch index d08eff7eaf..c7a70db167 100644 --- a/tests/incremental/11-restart/09-call-remove.patch +++ b/tests/incremental/11-restart/09-call-remove.patch @@ -1,5 +1,5 @@ ---- a/tests/incremental/11-restart/09-call-remove.c -+++ b/tests/incremental/11-restart/09-call-remove.c +--- tests/incremental/11-restart/09-call-remove.c ++++ tests/incremental/11-restart/09-call-remove.c @@ -8,7 +8,7 @@ } diff --git a/tests/incremental/11-restart/11-paper-example.patch b/tests/incremental/11-restart/11-paper-example.patch index fb15f57679..a8ccc46652 100644 --- a/tests/incremental/11-restart/11-paper-example.patch +++ b/tests/incremental/11-restart/11-paper-example.patch @@ -1,5 +1,5 @@ ---- a/tests/incremental/11-restart/11-paper-example.c -+++ b/tests/incremental/11-restart/11-paper-example.c +--- tests/incremental/11-restart/11-paper-example.c ++++ tests/incremental/11-restart/11-paper-example.c @@ -20,7 +20,7 @@ void* consumer(void *arg) { res = fp(); } diff --git a/tests/incremental/11-restart/48-local-wpoint-funcall.c b/tests/incremental/11-restart/48-local-wpoint-funcall.c index 410ff7cccb..d9d41760de 100644 --- a/tests/incremental/11-restart/48-local-wpoint-funcall.c +++ b/tests/incremental/11-restart/48-local-wpoint-funcall.c @@ -13,6 +13,6 @@ int main() { assert(x == 0); // FAIL before, success after } - assert(0); // FAIL before, nothing after + assert(0); // FAIL before, nowarn after return 0; } \ No newline at end of file diff --git a/tests/incremental/11-restart/48-local-wpoint-funcall.json b/tests/incremental/11-restart/48-local-wpoint-funcall.json index 01e6f27a23..b8ff84da1e 100644 --- a/tests/incremental/11-restart/48-local-wpoint-funcall.json +++ b/tests/incremental/11-restart/48-local-wpoint-funcall.json @@ -4,11 +4,19 @@ "interval": true } }, - "incremental": { - "restart": { - "wpoint": { - "enabled": false - } - } - } + "exp": { + "solver": { + "td3": { + "restart": { + "wpoint": { + "enabled": true, + "once": true + } + }, + "abort": false, + "abort-verify": false + } + } + } + } \ No newline at end of file diff --git a/tests/incremental/11-restart/48-local-wpoint-funcall.patch b/tests/incremental/11-restart/48-local-wpoint-funcall.patch index 34d33acb08..6a8c48b512 100644 --- a/tests/incremental/11-restart/48-local-wpoint-funcall.patch +++ b/tests/incremental/11-restart/48-local-wpoint-funcall.patch @@ -1,5 +1,5 @@ ---- a/tests/incremental/11-restart/48-local-wpoint-funcall.c -+++ b/tests/incremental/11-restart/48-local-wpoint-funcall.c +--- tests/incremental/11-restart/48-local-wpoint-funcall.c ++++ tests/incremental/11-restart/48-local-wpoint-funcall.c @@ -1,7 +1,7 @@ #include @@ -9,7 +9,6 @@ } int main() { - @@ -10,9 +10,9 @@ int main() { while (x < 10) { y = f(x); @@ -18,7 +17,7 @@ + assert(x == 0); // fail before, SUCCESS after } -- assert(0); // FAIL before, nothing after +- assert(0); // FAIL before, nowarn after + assert(0); // fail before, NOWARN after return 0; } diff --git a/tests/incremental/12-abort/01-abort_aget.patch b/tests/incremental/12-abort/01-abort_aget.patch index 657688e79f..ac5c9f4c6b 100644 --- a/tests/incremental/12-abort/01-abort_aget.patch +++ b/tests/incremental/12-abort/01-abort_aget.patch @@ -1,5 +1,5 @@ ---- a/tests/incremental/12-abort/01-abort_aget.c -+++ b/tests/incremental/12-abort/01-abort_aget.c +--- tests/incremental/12-abort/01-abort_aget.c ++++ tests/incremental/12-abort/01-abort_aget.c @@ -4,7 +4,7 @@ void b(); void c() {} diff --git a/tests/incremental/12-abort/02-abort-smtprc.patch b/tests/incremental/12-abort/02-abort-smtprc.patch index 51110a81ef..74a2e64e2d 100644 --- a/tests/incremental/12-abort/02-abort-smtprc.patch +++ b/tests/incremental/12-abort/02-abort-smtprc.patch @@ -1,5 +1,5 @@ ---- a/tests/incremental/12-abort/02-abort-smtprc.c -+++ b/tests/incremental/12-abort/02-abort-smtprc.c +--- tests/incremental/12-abort/02-abort-smtprc.c ++++ tests/incremental/12-abort/02-abort-smtprc.c @@ -26,7 +26,7 @@ int i(int l) { while (m) { f(l); From d26310ffb131ce9da239c8e0479a630a56e08f39 Mon Sep 17 00:00:00 2001 From: Vesal Vojdani Date: Wed, 22 Dec 2021 17:06:56 +0200 Subject: [PATCH 144/402] Fix header (how did this escape??) --- tests/incremental/11-restart/04-global-add.patch | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/incremental/11-restart/04-global-add.patch b/tests/incremental/11-restart/04-global-add.patch index 8aa80bb000..246b27a61d 100644 --- a/tests/incremental/11-restart/04-global-add.patch +++ b/tests/incremental/11-restart/04-global-add.patch @@ -1,5 +1,5 @@ ---- a/tests/incremental/11-restart/04-global-add.c -+++ b/tests/incremental/11-restart/04-global-add.c +--- tests/incremental/11-restart/04-global-add.c ++++ tests/incremental/11-restart/04-global-add.c @@ -4,7 +4,7 @@ int g = 1; From c0cbe3dec5e5ac39a2ecacb26d4ed596d0acf6b4 Mon Sep 17 00:00:00 2001 From: Vesal Vojdani Date: Wed, 22 Dec 2021 17:07:24 +0200 Subject: [PATCH 145/402] Check if some patch fails to apply. --- scripts/update_suite.rb | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/scripts/update_suite.rb b/scripts/update_suite.rb index 51fa8b1603..996494e821 100755 --- a/scripts/update_suite.rb +++ b/scripts/update_suite.rb @@ -406,8 +406,13 @@ def create_test_set(lines) super(lines) @testset.p = self `patch -p0 -b <#{patch_path}` + status = $?.exitstatus lines_incr = IO.readlines(path) `patch -p0 -b -R <#{patch_path}` + if status != 0 + puts "Failed to apply patch: #{patch_path}" + exit 1 + end @testset_incr = parse_tests(lines_incr) @testset_incr.p = self @testset_incr.warnfile = File.join($testresults, group, name + ".incr.warn.txt") From 32f0d1d915c627ed51a6f1de0a931bd9bfa25bcf Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 22 Dec 2021 21:24:04 +0200 Subject: [PATCH 146/402] Document schema usage for incremental tests --- docs/user-guide/configuring.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/user-guide/configuring.md b/docs/user-guide/configuring.md index 36055a6c91..72d5d39a8c 100644 --- a/docs/user-guide/configuring.md +++ b/docs/user-guide/configuring.md @@ -11,7 +11,8 @@ In `.vscode/settings.json` add the following: "json.schemas": [ { "fileMatch": [ - "/conf/*.json" + "/conf/*.json", + "/tests/incremental/*/*.json" ], "url": "/src/util/options.schema.json" } From 6af185bd2719d7a931d213cb9c603a87a7dd0705 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 22 Dec 2021 21:24:35 +0200 Subject: [PATCH 147/402] Fix invalid conf of incremental/11-restart/08-side-restart --- tests/incremental/11-restart/08-side-restart.json | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/tests/incremental/11-restart/08-side-restart.json b/tests/incremental/11-restart/08-side-restart.json index 88d0b04778..204d3352a7 100644 --- a/tests/incremental/11-restart/08-side-restart.json +++ b/tests/incremental/11-restart/08-side-restart.json @@ -7,12 +7,17 @@ "incremental": { "reluctant": { "on": false - }, - "restart": { - "wpoint": { - "enabled": false + } + }, + "exp": { + "solver": { + "td3": { + "restart": { + "wpoint": { + "enabled": false + } + } } } - } } \ No newline at end of file From 25fcc2118f0be3c30a3d45403b437447d734bb19 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Mon, 10 Jan 2022 14:04:45 +0200 Subject: [PATCH 148/402] Fix params of 34-localwn_restart/04-hh --- tests/regression/34-localwn_restart/04-hh.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/regression/34-localwn_restart/04-hh.c b/tests/regression/34-localwn_restart/04-hh.c index 46bd53ed4c..24e82cc105 100644 --- a/tests/regression/34-localwn_restart/04-hh.c +++ b/tests/regression/34-localwn_restart/04-hh.c @@ -1,7 +1,7 @@ -// SKIP PARAM: --enable ana.int.interval --set solver td3 --enable exp.partition-arrays.enabled --set ana.activated "['base','threadid','threadflag','expRelation','mallocWrapper','apron']" --set exp.privatization none --set exp.apron.privatization dummy --set sem.int.signed_overflow assume_none +// SKIP PARAM: --enable ana.int.interval --set solver td3 --enable ana.base.partition-arrays.enabled --set ana.activated "['base','threadid','threadflag','expRelation','mallocWrapper','apron']" --set ana.base.privatization none --set ana.apron.privatization dummy --set sem.int.signed_overflow assume_none // This is part of 34-localization, but also symlinked to 36-apron. -// ALSO: --enable ana.int.interval --set solver slr3 --enable exp.partition-arrays.enabled --set ana.activated "['base','threadid','threadflag','expRelation','mallocWrapper','apron']" --set exp.privatization none --set exp.apron.privatization dummy --set sem.int.signed_overflow assume_none +// ALSO: --enable ana.int.interval --set solver slr3 --enable ana.base.partition-arrays.enabled --set ana.activated "['base','threadid','threadflag','expRelation','mallocWrapper','apron']" --set ana.base.privatization none --set ana.apron.privatization dummy --set sem.int.signed_overflow assume_none // Example from Halbwachs-Henry, SAS 2012 // Localized widening or restart policy should be able to prove that i <= j+3 // if the abstract domain is powerful enough. From 767085f4052ea4c9584d1178ce5c45d5d106f056 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Mon, 10 Jan 2022 16:08:55 +0200 Subject: [PATCH 149/402] Print TD3 data after postsolve --- src/solvers/td3.ml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/solvers/td3.ml b/src/solvers/td3.ml index 5cef744212..4cff35dfc5 100644 --- a/src/solvers/td3.ml +++ b/src/solvers/td3.ml @@ -903,6 +903,8 @@ module WP = Post.post st vs rho; + print_data data "Data after postsolve"; + {st; infl; sides; rho; wpoint; stable; side_dep; side_infl; var_messages} let solve box st vs = From 7e834257361484b938df2df1d58f57e8419c2a98 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Tue, 11 Jan 2022 14:15:10 +0200 Subject: [PATCH 150/402] Add incremental test for dead branches --- tests/incremental/00-basic/07-dead-branch.c | 16 ++++++++++++++++ tests/incremental/00-basic/07-dead-branch.json | 5 +++++ tests/incremental/00-basic/07-dead-branch.patch | 11 +++++++++++ 3 files changed, 32 insertions(+) create mode 100644 tests/incremental/00-basic/07-dead-branch.c create mode 100644 tests/incremental/00-basic/07-dead-branch.json create mode 100644 tests/incremental/00-basic/07-dead-branch.patch diff --git a/tests/incremental/00-basic/07-dead-branch.c b/tests/incremental/00-basic/07-dead-branch.c new file mode 100644 index 0000000000..454b41e351 --- /dev/null +++ b/tests/incremental/00-basic/07-dead-branch.c @@ -0,0 +1,16 @@ +#include + +void foo() { + +} + +int main() { + int a = 1; + + if (a) // WARN + assert(a); + + foo(); + + return 0; +} \ No newline at end of file diff --git a/tests/incremental/00-basic/07-dead-branch.json b/tests/incremental/00-basic/07-dead-branch.json new file mode 100644 index 0000000000..1ad6fa9f48 --- /dev/null +++ b/tests/incremental/00-basic/07-dead-branch.json @@ -0,0 +1,5 @@ +{ + "dbg": { + "print_dead_code": true + } +} diff --git a/tests/incremental/00-basic/07-dead-branch.patch b/tests/incremental/00-basic/07-dead-branch.patch new file mode 100644 index 0000000000..fa7ba3b9da --- /dev/null +++ b/tests/incremental/00-basic/07-dead-branch.patch @@ -0,0 +1,11 @@ +--- tests/incremental/00-basic/07-dead-branch.c ++++ tests/incremental/00-basic/07-dead-branch.c +@@ -1,7 +1,7 @@ + #include + + void foo() { +- ++ assert(1); + } + + int main() { From c5948e847f1da44bb6d076253ac1e73df0cd162c Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Tue, 11 Jan 2022 14:33:28 +0200 Subject: [PATCH 151/402] Add regression test for multiple dead branches --- tests/regression/01-cpa/55-dead-branch-multiple.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 tests/regression/01-cpa/55-dead-branch-multiple.c diff --git a/tests/regression/01-cpa/55-dead-branch-multiple.c b/tests/regression/01-cpa/55-dead-branch-multiple.c new file mode 100644 index 0000000000..8a0c7a9bd7 --- /dev/null +++ b/tests/regression/01-cpa/55-dead-branch-multiple.c @@ -0,0 +1,12 @@ +#include + +int main() { + int a = 1; + int b = 0; + + if (a && b) { // TODO WARN + assert(0); // NOWARN (unreachable) + } + + return 0; +} From d60ed7e5dcf324a49964ef9259ea2cad8ba88fd5 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Tue, 11 Jan 2022 14:33:47 +0200 Subject: [PATCH 152/402] Add Node global variables to DeadBranchLifter --- src/framework/constraints.ml | 56 ++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/src/framework/constraints.ml b/src/framework/constraints.ml index bb9e24adc8..e650c3c80e 100644 --- a/src/framework/constraints.ml +++ b/src/framework/constraints.ml @@ -1058,6 +1058,62 @@ struct let name () = "DeadBranch (" ^ name () ^ ")" + module V = + struct + include Printable.Either (S.V) (Node) + let s x = `Left x + let node x = `Right x + end + + module G = + struct + include Lattice.Lift2 (S.G) (BoolDomain.MayBool) (Printable.DefaultNames) + + let s = function + | `Bot -> S.G.bot () + | `Lifted1 x -> x + | _ -> failwith "DeadBranchLifter.s" + let node = function + | `Bot -> BoolDomain.MayBool.bot () + | `Lifted2 x -> x + | _ -> failwith "DeadBranchLifter.node" + let create_s s = `Lifted1 s + let create_node node = `Lifted2 node + end + + let conv (ctx: (_, G.t, _, V.t) ctx): (_, S.G.t, _, S.V.t) ctx = + { ctx with + global = (fun v -> G.s (ctx.global (V.s v))); + sideg = (fun v g -> ctx.sideg (V.s v) (G.create_s g)); + } + + let sync ctx = S.sync (conv ctx) + let query ctx (type a) (q: a Queries.t): a Queries.result = + match q with + | WarnGlobal g -> + let g: V.t = Obj.obj g in + begin match g with + | `Left g -> + S.query (conv ctx) (WarnGlobal (Obj.repr g)) + | `Right g -> + failwith "a" + end + | _ -> + S.query (conv ctx) q + let assign ctx = S.assign (conv ctx) + let vdecl ctx = S.vdecl (conv ctx) + let branch ctx = S.branch (conv ctx) + let body ctx = S.body (conv ctx) + let return ctx = S.return (conv ctx) + let intrpt ctx = S.intrpt (conv ctx) + let asm ctx = S.asm (conv ctx) + let skip ctx = S.skip (conv ctx) + let special ctx = S.special (conv ctx) + let enter ctx = S.enter (conv ctx) + let combine ctx = S.combine (conv ctx) + let threadenter ctx = S.threadenter (conv ctx) + let threadspawn ctx lv f args fctx = S.threadspawn (conv ctx) lv f args (conv fctx) + module Locmap = Deadcode.Locmap let dead_branches = function true -> Deadcode.dead_branches_then | false -> Deadcode.dead_branches_else From dfad2ad81e395b8b37ec49b914540f318776a791 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Tue, 11 Jan 2022 15:09:00 +0200 Subject: [PATCH 153/402] Add dead branch warnings via global invariant --- src/framework/constraints.ml | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/src/framework/constraints.ml b/src/framework/constraints.ml index e650c3c80e..3edb5b36ee 100644 --- a/src/framework/constraints.ml +++ b/src/framework/constraints.ml @@ -1065,16 +1065,22 @@ struct let node x = `Right x end + module GB = + struct + include Basetype.Bools + let leq x y = !GU.postsolving || leq x y (* HACK: to pass verify*) + end + module G = struct - include Lattice.Lift2 (S.G) (BoolDomain.MayBool) (Printable.DefaultNames) + include Lattice.Lift2 (S.G) (GB) (Printable.DefaultNames) let s = function | `Bot -> S.G.bot () | `Lifted1 x -> x | _ -> failwith "DeadBranchLifter.s" let node = function - | `Bot -> BoolDomain.MayBool.bot () + | `Bot -> GB.bot () | `Lifted2 x -> x | _ -> failwith "DeadBranchLifter.node" let create_s s = `Lifted1 s @@ -1096,7 +1102,12 @@ struct | `Left g -> S.query (conv ctx) (WarnGlobal (Obj.repr g)) | `Right g -> - failwith "a" + begin match G.node (ctx.global (V.node g)) with + | `Lifted tv -> + M.warn ~loc:(Node.location g) ~category:Deadcode "DEAD BRANCH" + | _ -> + () + end end | _ -> S.query (conv ctx) q @@ -1125,14 +1136,18 @@ struct let r = branch ctx exp tv in (* branch is live *) Locmap.replace (dead_branches tv) !Tracing.current_loc false; (* set to live (false) *) + ctx.sideg (V.node ctx.prev_node) (G.create_node (`Lifted tv)); r with Deadcode -> (* branch is dead *) Locmap.modify_def true !Tracing.current_loc Fun.id (dead_branches tv); (* set to dead (true) if not mem, otherwise keep existing (Fun.id) since it may be live (false) in another context *) + ctx.sideg (V.node ctx.prev_node) (G.create_node `Bot); raise Deadcode ) - else + else ( + ctx.sideg (V.node ctx.prev_node) (G.create_node `Bot); branch ctx exp tv + ) end module Compare From b9dde351dd8c46915aaaa98cc8c2399574749692 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Tue, 11 Jan 2022 15:21:13 +0200 Subject: [PATCH 154/402] Add expressions to global invariant based dead branch --- src/cdomains/basetype.ml | 1 + src/framework/constraints.ml | 28 +++++++++++++++------------- 2 files changed, 16 insertions(+), 13 deletions(-) diff --git a/src/cdomains/basetype.ml b/src/cdomains/basetype.ml index 8f00d326a3..c3f39efb12 100644 --- a/src/cdomains/basetype.ml +++ b/src/cdomains/basetype.ml @@ -83,6 +83,7 @@ module Bools: Lattice.S with type t = [`Bot | `Lifted of bool | `Top] = module CilExp = struct + include Printable.Std (* for Groupable *) include CilType.Exp let copy x = x diff --git a/src/framework/constraints.ml b/src/framework/constraints.ml index 3edb5b36ee..37d97d1dc1 100644 --- a/src/framework/constraints.ml +++ b/src/framework/constraints.ml @@ -1065,22 +1065,22 @@ struct let node x = `Right x end - module GB = + module EM = struct - include Basetype.Bools + include MapDomain.MapBot (Basetype.CilExp) (Basetype.Bools) let leq x y = !GU.postsolving || leq x y (* HACK: to pass verify*) end module G = struct - include Lattice.Lift2 (S.G) (GB) (Printable.DefaultNames) + include Lattice.Lift2 (S.G) (EM) (Printable.DefaultNames) let s = function | `Bot -> S.G.bot () | `Lifted1 x -> x | _ -> failwith "DeadBranchLifter.s" let node = function - | `Bot -> GB.bot () + | `Bot -> EM.bot () | `Lifted2 x -> x | _ -> failwith "DeadBranchLifter.node" let create_s s = `Lifted1 s @@ -1102,12 +1102,14 @@ struct | `Left g -> S.query (conv ctx) (WarnGlobal (Obj.repr g)) | `Right g -> - begin match G.node (ctx.global (V.node g)) with - | `Lifted tv -> - M.warn ~loc:(Node.location g) ~category:Deadcode "DEAD BRANCH" - | _ -> - () - end + let em = G.node (ctx.global (V.node g)) in + EM.iter (fun exp tv -> + match tv with + | `Lifted tv -> + M.warn ~loc:(Node.location g) ~tags:[CWE (if tv then 571 else 570)] ~category:Deadcode "condition '%a' is always %B" d_exp exp tv + | _ -> + () + ) em; end | _ -> S.query (conv ctx) q @@ -1136,16 +1138,16 @@ struct let r = branch ctx exp tv in (* branch is live *) Locmap.replace (dead_branches tv) !Tracing.current_loc false; (* set to live (false) *) - ctx.sideg (V.node ctx.prev_node) (G.create_node (`Lifted tv)); + ctx.sideg (V.node ctx.prev_node) (G.create_node (EM.singleton exp (`Lifted tv))); r with Deadcode -> (* branch is dead *) Locmap.modify_def true !Tracing.current_loc Fun.id (dead_branches tv); (* set to dead (true) if not mem, otherwise keep existing (Fun.id) since it may be live (false) in another context *) - ctx.sideg (V.node ctx.prev_node) (G.create_node `Bot); + ctx.sideg (V.node ctx.prev_node) (G.create_node (EM.singleton exp `Bot)); raise Deadcode ) else ( - ctx.sideg (V.node ctx.prev_node) (G.create_node `Bot); + ctx.sideg (V.node ctx.prev_node) (G.create_node (EM.bot ())); branch ctx exp tv ) end From cba9b143912ac25864ef8c99132191e0f99a55cd Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Tue, 11 Jan 2022 15:24:20 +0200 Subject: [PATCH 155/402] Remove global data structure for dead branch --- src/framework/constraints.ml | 6 ------ src/framework/control.ml | 14 -------------- src/util/deadcode.ml | 4 ---- 3 files changed, 24 deletions(-) diff --git a/src/framework/constraints.ml b/src/framework/constraints.ml index 37d97d1dc1..213db0acef 100644 --- a/src/framework/constraints.ml +++ b/src/framework/constraints.ml @@ -1127,22 +1127,16 @@ struct let threadenter ctx = S.threadenter (conv ctx) let threadspawn ctx lv f args fctx = S.threadspawn (conv ctx) lv f args (conv fctx) - module Locmap = Deadcode.Locmap - - let dead_branches = function true -> Deadcode.dead_branches_then | false -> Deadcode.dead_branches_else let branch ctx exp tv = if !GU.postsolving then ( - Locmap.replace Deadcode.dead_branches_cond !Tracing.current_loc exp; try let r = branch ctx exp tv in (* branch is live *) - Locmap.replace (dead_branches tv) !Tracing.current_loc false; (* set to live (false) *) ctx.sideg (V.node ctx.prev_node) (G.create_node (EM.singleton exp (`Lifted tv))); r with Deadcode -> (* branch is dead *) - Locmap.modify_def true !Tracing.current_loc Fun.id (dead_branches tv); (* set to dead (true) if not mem, otherwise keep existing (Fun.id) since it may be live (false) in another context *) ctx.sideg (V.node ctx.prev_node) (G.create_node (EM.singleton exp `Bot)); raise Deadcode ) diff --git a/src/framework/control.ml b/src/framework/control.ml index 38e3f13547..db259f0f30 100644 --- a/src/framework/control.ml +++ b/src/framework/control.ml @@ -148,20 +148,6 @@ struct ); printf "Total lines (logical LoC): %d\n" (live_count + !count + uncalled_fn_loc); (* We can only give total LoC if we counted dead code *) ); - let str = function true -> "then" | false -> "else" in - let report tv (loc, dead) = - match dead, Deadcode.Locmap.find_option Deadcode.dead_branches_cond loc with - | true, Some exp -> M.warn ~loc ~category:Deadcode ~tags:[CWE (if tv then 570 else 571)] "the %s branch over expression '%a' is dead" (str tv) d_exp exp - | true, None -> M.warn ~loc ~category:Deadcode ~tags:[CWE (if tv then 570 else 571)] "an %s branch is dead" (str tv) - | _ -> () - in - if get_bool "dbg.print_dead_code" then ( - let by_fst (a,_) (b,_) = Stdlib.compare a b in - Deadcode.Locmap.to_list Deadcode.dead_branches_then |> List.sort by_fst |> List.iter (report true) ; - Deadcode.Locmap.to_list Deadcode.dead_branches_else |> List.sort by_fst |> List.iter (report false) ; - Deadcode.Locmap.clear Deadcode.dead_branches_then; - Deadcode.Locmap.clear Deadcode.dead_branches_else - ); NH.mem live_nodes (* convert result that can be out-put *) diff --git a/src/util/deadcode.ml b/src/util/deadcode.ml index 9915b3c9cc..5a0c7c7773 100644 --- a/src/util/deadcode.ml +++ b/src/util/deadcode.ml @@ -1,5 +1 @@ module Locmap = BatHashtbl.Make (CilType.Location) - -let dead_branches_then : bool Locmap.t = Locmap.create 10 -let dead_branches_else : bool Locmap.t = Locmap.create 10 -let dead_branches_cond : Cil.exp Locmap.t = Locmap.create 10 From a568e3ed1bf7e2fa50b625b0945a088247e5efbf Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Tue, 11 Jan 2022 15:25:39 +0200 Subject: [PATCH 156/402] Remove Deadcode module --- src/framework/control.ml | 5 +++-- src/util/deadcode.ml | 1 - 2 files changed, 3 insertions(+), 3 deletions(-) delete mode 100644 src/util/deadcode.ml diff --git a/src/framework/control.ml b/src/framework/control.ml index db259f0f30..bce054bda8 100644 --- a/src/framework/control.ml +++ b/src/framework/control.ml @@ -70,7 +70,8 @@ struct (* print out information about dead code *) let print_dead_code (xs:Result.t) uncalled_fn_loc = - let dead_locations : unit Deadcode.Locmap.t = Deadcode.Locmap.create 10 in + let module Locmap = BatHashtbl.Make (CilType.Location) in + let dead_locations : unit Locmap.t = Locmap.create 10 in let module NH = Hashtbl.Make (Node) in let live_nodes : unit NH.t = NH.create 10 in let count = ref 0 in (* Is only populated if "dbg.print_dead_code" is true *) @@ -88,7 +89,7 @@ struct let is_dead = LT.for_all (fun (_,x,f) -> Spec.D.is_bot x) v in if is_dead then ( dead_lines := StringMap.modify_def StringMap.empty l.file add_file !dead_lines; - Deadcode.Locmap.add dead_locations l (); + Locmap.add dead_locations l (); ) else ( live_lines := StringMap.modify_def StringMap.empty l.file add_file !live_lines; NH.add live_nodes n () diff --git a/src/util/deadcode.ml b/src/util/deadcode.ml deleted file mode 100644 index 5a0c7c7773..0000000000 --- a/src/util/deadcode.ml +++ /dev/null @@ -1 +0,0 @@ -module Locmap = BatHashtbl.Make (CilType.Location) From d3a046ec004c0ddd50b9dd7ad30a7c982cf395d4 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Tue, 11 Jan 2022 15:26:08 +0200 Subject: [PATCH 157/402] Remove unused dead_locations variable --- src/framework/control.ml | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/framework/control.ml b/src/framework/control.ml index bce054bda8..f6ce566bf5 100644 --- a/src/framework/control.ml +++ b/src/framework/control.ml @@ -70,8 +70,6 @@ struct (* print out information about dead code *) let print_dead_code (xs:Result.t) uncalled_fn_loc = - let module Locmap = BatHashtbl.Make (CilType.Location) in - let dead_locations : unit Locmap.t = Locmap.create 10 in let module NH = Hashtbl.Make (Node) in let live_nodes : unit NH.t = NH.create 10 in let count = ref 0 in (* Is only populated if "dbg.print_dead_code" is true *) @@ -88,8 +86,7 @@ struct let add_file = StringMap.modify_def BatISet.empty f.svar.vname add_fun in let is_dead = LT.for_all (fun (_,x,f) -> Spec.D.is_bot x) v in if is_dead then ( - dead_lines := StringMap.modify_def StringMap.empty l.file add_file !dead_lines; - Locmap.add dead_locations l (); + dead_lines := StringMap.modify_def StringMap.empty l.file add_file !dead_lines ) else ( live_lines := StringMap.modify_def StringMap.empty l.file add_file !live_lines; NH.add live_nodes n () From 72cb6e3806f11c2d9f17c3b625519f4b7de0bae0 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Tue, 11 Jan 2022 15:36:52 +0200 Subject: [PATCH 158/402] Clean up DeadBranchLifter --- src/framework/constraints.ml | 41 +++++++++++++++++++----------------- 1 file changed, 22 insertions(+), 19 deletions(-) diff --git a/src/framework/constraints.ml b/src/framework/constraints.ml index 213db0acef..0caab045ea 100644 --- a/src/framework/constraints.ml +++ b/src/framework/constraints.ml @@ -1056,7 +1056,7 @@ module DeadBranchLifter (S: Spec): Spec = struct include S - let name () = "DeadBranch (" ^ name () ^ ")" + let name () = "DeadBranch (" ^ S.name () ^ ")" module V = struct @@ -1093,7 +1093,6 @@ struct sideg = (fun v g -> ctx.sideg (V.s v) (G.create_s g)); } - let sync ctx = S.sync (conv ctx) let query ctx (type a) (q: a Queries.t): a Queries.result = match q with | WarnGlobal g -> @@ -1107,43 +1106,47 @@ struct match tv with | `Lifted tv -> M.warn ~loc:(Node.location g) ~tags:[CWE (if tv then 571 else 570)] ~category:Deadcode "condition '%a' is always %B" d_exp exp tv - | _ -> + | `Bot (* all branches dead? can happen at our inserted Neg(1)-s because no Pos(1) *) + | `Top -> (* may be both true and false *) () ) em; end | _ -> S.query (conv ctx) q - let assign ctx = S.assign (conv ctx) - let vdecl ctx = S.vdecl (conv ctx) - let branch ctx = S.branch (conv ctx) - let body ctx = S.body (conv ctx) - let return ctx = S.return (conv ctx) - let intrpt ctx = S.intrpt (conv ctx) - let asm ctx = S.asm (conv ctx) - let skip ctx = S.skip (conv ctx) - let special ctx = S.special (conv ctx) - let enter ctx = S.enter (conv ctx) - let combine ctx = S.combine (conv ctx) - let threadenter ctx = S.threadenter (conv ctx) - let threadspawn ctx lv f args fctx = S.threadspawn (conv ctx) lv f args (conv fctx) + let branch ctx = S.branch (conv ctx) + let branch ctx exp tv = if !GU.postsolving then ( try let r = branch ctx exp tv in (* branch is live *) - ctx.sideg (V.node ctx.prev_node) (G.create_node (EM.singleton exp (`Lifted tv))); + ctx.sideg (V.node ctx.prev_node) (G.create_node (EM.singleton exp (`Lifted tv))); (* record expression with reached tv *) r with Deadcode -> (* branch is dead *) - ctx.sideg (V.node ctx.prev_node) (G.create_node (EM.singleton exp `Bot)); + ctx.sideg (V.node ctx.prev_node) (G.create_node (EM.singleton exp `Bot)); (* record expression without reached tv *) raise Deadcode ) else ( - ctx.sideg (V.node ctx.prev_node) (G.create_node (EM.bot ())); + ctx.sideg (V.node ctx.prev_node) (G.create_node (EM.bot ())); (* create global variable during solving, to allow postsolving leq hack to pass verify *) branch ctx exp tv ) + + let assign ctx = S.assign (conv ctx) + let vdecl ctx = S.vdecl (conv ctx) + let enter ctx = S.enter (conv ctx) + let body ctx = S.body (conv ctx) + let return ctx = S.return (conv ctx) + let combine ctx = S.combine (conv ctx) + let special ctx = S.special (conv ctx) + let threadenter ctx = S.threadenter (conv ctx) + let threadspawn ctx lv f args fctx = S.threadspawn (conv ctx) lv f args (conv fctx) + let sync ctx = S.sync (conv ctx) + let skip ctx = S.skip (conv ctx) + let asm ctx = S.asm (conv ctx) + let intrpt ctx = S.intrpt (conv ctx) end module Compare From ffec4686224f28aea072f07418cc03cf8c6c260f Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Tue, 11 Jan 2022 16:00:24 +0200 Subject: [PATCH 159/402] Fix HTML globals with DeadBranchLifter --- src/framework/constraints.ml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/framework/constraints.ml b/src/framework/constraints.ml index 0caab045ea..13277d2651 100644 --- a/src/framework/constraints.ml +++ b/src/framework/constraints.ml @@ -1085,6 +1085,11 @@ struct | _ -> failwith "DeadBranchLifter.node" let create_s s = `Lifted1 s let create_node node = `Lifted2 node + + let printXml f = function + | `Lifted1 x -> S.G.printXml f x + | `Lifted2 x -> BatPrintf.fprintf f "%a" EM.printXml x + | x -> BatPrintf.fprintf f "%a" printXml x end let conv (ctx: (_, G.t, _, V.t) ctx): (_, S.G.t, _, S.V.t) ctx = From c4362e1e288cff427b8703c46ef00377d08193d1 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Fri, 14 Jan 2022 12:05:31 +0200 Subject: [PATCH 160/402] Add node field to message piece --- src/framework/myCFG.ml | 2 +- src/framework/node.ml | 13 +------------ src/framework/nodeType.ml | 14 ++++++++++++++ src/util/messages.ml | 15 ++++++++------- 4 files changed, 24 insertions(+), 20 deletions(-) create mode 100644 src/framework/nodeType.ml diff --git a/src/framework/myCFG.ml b/src/framework/myCFG.ml index ed2efd7bcc..5f994a1e7f 100644 --- a/src/framework/myCFG.ml +++ b/src/framework/myCFG.ml @@ -45,7 +45,7 @@ end module NodeH = BatHashtbl.Make (Node) -let current_node : node option ref = ref None +let current_node = Node.current_node let unknown_exp : exp = mkString "__unknown_value__" let dummy_func = emptyFunction "__goblint_dummy_init" (* TODO get rid of this? *) diff --git a/src/framework/node.ml b/src/framework/node.ml index cdefacbe95..4809032a82 100644 --- a/src/framework/node.ml +++ b/src/framework/node.ml @@ -3,18 +3,7 @@ open Pretty include Printable.Std -(** A node in the Control Flow Graph is either a statement or function. Think of - * the function node as last node that all the returning nodes point to. So - * the result of the function call is contained in the function node. *) -type t = - | Statement of CilType.Stmt.t - (** The statements as identified by CIL *) - (* The stmt in a Statement node is misleading because nodes are program points between transfer functions (edges), which actually correspond to statement execution. *) - | FunctionEntry of CilType.Fundec.t - (** *) - | Function of CilType.Fundec.t - (** The variable information associated with the function declaration. *) -[@@deriving eq, ord, to_yojson] +include NodeType let name () = "node" diff --git a/src/framework/nodeType.ml b/src/framework/nodeType.ml new file mode 100644 index 0000000000..1674547fab --- /dev/null +++ b/src/framework/nodeType.ml @@ -0,0 +1,14 @@ +(** A node in the Control Flow Graph is either a statement or function. Think of + * the function node as last node that all the returning nodes point to. So + * the result of the function call is contained in the function node. *) +type t = + | Statement of CilType.Stmt.t + (** The statements as identified by CIL *) + (* The stmt in a Statement node is misleading because nodes are program points between transfer functions (edges), which actually correspond to statement execution. *) + | FunctionEntry of CilType.Fundec.t + (** *) + | Function of CilType.Fundec.t + (** The variable information associated with the function declaration. *) +[@@deriving eq, ord, to_yojson] + +let current_node: t option ref = ref None diff --git a/src/util/messages.ml b/src/util/messages.ml index 1701bfb656..3fbc139ba6 100644 --- a/src/util/messages.ml +++ b/src/util/messages.ml @@ -33,12 +33,13 @@ module Piece = struct type t = { loc: CilType.Location.t option; (* only *_each warnings have this, used for deduplication *) + node: NodeType.t option; text: string; context: (Obj.t [@equal fun x y -> Hashtbl.hash (Obj.obj x) = Hashtbl.hash (Obj.obj y)] [@to_yojson fun x -> `Int (Hashtbl.hash (Obj.obj x))]) option; (* TODO: this equality is terrible... *) } [@@deriving eq, to_yojson] - let hash {loc; text; context} = - 7 * BatOption.map_default CilType.Location.hash 1 loc + 9 * Hashtbl.hash text + 11 * BatOption.map_default (fun c -> Hashtbl.hash (Obj.obj c)) 1 context + let hash {loc; node; text; context} = + 7 * BatOption.map_default CilType.Location.hash 1 loc + 9 * Hashtbl.hash text + 11 * BatOption.map_default (fun c -> Hashtbl.hash (Obj.obj c)) 1 context (* TODO: use node *) let text_with_context {text; context; _} = match context with @@ -203,7 +204,7 @@ let add m = (** Adapts old [print_group] to new message structure. Don't use for new (group) warnings. *) let msg_group_race_old severity group_name errors = - let m = Message.{tags = [Category Race]; severity; multipiece = Group {group_text = group_name; pieces = List.map (fun (s, loc) -> Piece.{loc = Some loc; text = s; context = None}) errors}} in + let m = Message.{tags = [Category Race]; severity; multipiece = Group {group_text = group_name; pieces = List.map (fun (s, loc) -> Piece.{loc = Some loc; node = None; text = s; context = None}) errors}} in (* TODO: use node? *) add m; if (get_bool "ana.osek.warnfiles") then @@ -225,17 +226,17 @@ let msg_context () = else None (* avoid identical messages from multiple contexts without any mention of context *) -let msg severity ?loc:(loc= !Tracing.current_loc) ?(tags=[]) ?(category=Category.Unknown) fmt = +let msg severity ?(loc= !Tracing.current_loc) ?(node= !NodeType.current_node) ?(tags=[]) ?(category=Category.Unknown) fmt = let finish doc = let text = Pretty.sprint ~width:max_int doc in - add {tags = Category category :: tags; severity; multipiece = Single {loc = Some loc; text; context = msg_context ()}} + add {tags = Category category :: tags; severity; multipiece = Single {loc = Some loc; node; text; context = msg_context ()}} in Pretty.gprintf finish fmt let msg_noloc severity ?(tags=[]) ?(category=Category.Unknown) fmt = let finish doc = let text = Pretty.sprint ~width:max_int doc in - add {tags = Category category :: tags; severity; multipiece = Single {loc = None; text; context = msg_context ()}} + add {tags = Category category :: tags; severity; multipiece = Single {loc = None; node = None; text; context = msg_context ()}} in Pretty.gprintf finish fmt @@ -244,7 +245,7 @@ let msg_group severity ?(tags=[]) ?(category=Category.Unknown) fmt = let group_text = Pretty.sprint ~width:max_int doc in let piece_of_msg (doc, loc) = let text = Pretty.sprint ~width:max_int doc in - Piece.{loc; text; context = None} + Piece.{loc; node = None; text; context = None} (* TODO: add node *) in add {tags = Category category :: tags; severity; multipiece = Group {group_text; pieces = List.map piece_of_msg msgs}} in From 15404b5e62d0feff2ef12243497bcd1db922b6f4 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Fri, 14 Jan 2022 12:21:33 +0200 Subject: [PATCH 161/402] Use node instead of loc in deadlock analysis --- src/analyses/deadlock.ml | 8 ++++---- src/cdomains/deadlockDomain.ml | 6 +++--- src/util/messages.ml | 18 +++++++++++------- 3 files changed, 18 insertions(+), 14 deletions(-) diff --git a/src/analyses/deadlock.ml b/src/analyses/deadlock.ml index 8ee2433aed..6de7c9564f 100644 --- a/src/analyses/deadlock.ml +++ b/src/analyses/deadlock.ml @@ -26,8 +26,8 @@ struct if !Goblintutil.postsolving then begin D.iter (fun e -> List.iter (fun (a,b) -> if ((MyLock.equal a e) && (MyLock.equal b newLock)) then ( - Messages.warn "Deadlock warning: Locking order %a, %a at %a, %a violates order at %a, %a." ValueDomain.Addr.pretty e.addr ValueDomain.Addr.pretty newLock.addr CilType.Location.pretty e.loc CilType.Location.pretty newLock.loc CilType.Location.pretty b.loc CilType.Location.pretty a.loc; - Messages.warn ~loc:a.loc "Deadlock warning: Locking order %a, %a at %a, %a violates order at %a, %a." ValueDomain.Addr.pretty newLock.addr ValueDomain.Addr.pretty e.addr CilType.Location.pretty b.loc CilType.Location.pretty a.loc CilType.Location.pretty e.loc CilType.Location.pretty newLock.loc; + Messages.warn "Deadlock warning: Locking order %a, %a at %a, %a violates order at %a, %a." ValueDomain.Addr.pretty e.addr ValueDomain.Addr.pretty newLock.addr CilType.Location.pretty (Node.location e.node) CilType.Location.pretty (Node.location newLock.node) CilType.Location.pretty (Node.location b.node) CilType.Location.pretty (Node.location a.node); + Messages.warn ~node:a.node "Deadlock warning: Locking order %a, %a at %a, %a violates order at %a, %a." ValueDomain.Addr.pretty newLock.addr ValueDomain.Addr.pretty e.addr CilType.Location.pretty (Node.location b.node) CilType.Location.pretty (Node.location a.node) CilType.Location.pretty (Node.location e.node) CilType.Location.pretty (Node.location newLock.node); ) else () ) !forbiddenList ) lockList; @@ -96,8 +96,8 @@ struct match LibraryFunctions.classify f.vname arglist with | `Lock (_, _, _) -> List.fold_left (fun d lockAddr -> - addLockingInfo {addr = lockAddr; loc = !Tracing.current_loc } ctx.local; - D.add {addr = lockAddr; loc = !Tracing.current_loc } ctx.local + addLockingInfo {addr = lockAddr; node = Option.get !NodeType.current_node } ctx.local; + D.add {addr = lockAddr; node = Option.get !NodeType.current_node } ctx.local ) ctx.local (eval_exp_addr (Analyses.ask_of_ctx ctx) (List.hd arglist)) | `Unlock -> let lockAddrs = eval_exp_addr (Analyses.ask_of_ctx ctx) (List.hd arglist) in diff --git a/src/cdomains/deadlockDomain.ml b/src/cdomains/deadlockDomain.ml index 607b3ab8f3..8136b167db 100644 --- a/src/cdomains/deadlockDomain.ml +++ b/src/cdomains/deadlockDomain.ml @@ -1,7 +1,7 @@ open Cil open Pretty -type myowntypeEntry = {addr : ValueDomain.Addr.t ; loc : location} +type myowntypeEntry = {addr : ValueDomain.Addr.t ; node : Node.t} module MyLock : Printable.S with type t = myowntypeEntry = @@ -15,8 +15,8 @@ struct let hash x = Ad.hash x.addr let compare x y = Ad.compare x.addr y.addr (* ignores loc field *) (* TODO: deadlock analysis output doesn't even use these, but manually outputs locations *) - let show x = (Ad.show x.addr) ^ "@" ^ (CilType.Location.show x.loc) - let pretty () x = Ad.pretty () x.addr ++ text "@" ++ CilType.Location.pretty () x.loc + let show x = (Ad.show x.addr) ^ "@" ^ (CilType.Location.show (Node.location x.node)) + let pretty () x = Ad.pretty () x.addr ++ text "@" ++ CilType.Location.pretty () (Node.location x.node) let printXml c x = Ad.printXml c x.addr let to_yojson x = `String (show x) end diff --git a/src/util/messages.ml b/src/util/messages.ml index 3fbc139ba6..11348daf87 100644 --- a/src/util/messages.ml +++ b/src/util/messages.ml @@ -226,10 +226,14 @@ let msg_context () = else None (* avoid identical messages from multiple contexts without any mention of context *) -let msg severity ?(loc= !Tracing.current_loc) ?(node= !NodeType.current_node) ?(tags=[]) ?(category=Category.Unknown) fmt = +let msg severity ?node ?(tags=[]) ?(category=Category.Unknown) fmt = let finish doc = let text = Pretty.sprint ~width:max_int doc in - add {tags = Category category :: tags; severity; multipiece = Single {loc = Some loc; node; text; context = msg_context ()}} + let node = match node with + | Some node -> Some node + | None -> !NodeType.current_node + in + add {tags = Category category :: tags; severity; multipiece = Single {loc = None; node; text; context = msg_context ()}} in Pretty.gprintf finish fmt @@ -252,15 +256,15 @@ let msg_group severity ?(tags=[]) ?(category=Category.Unknown) fmt = Pretty.gprintf finish fmt (* must eta-expand to get proper (non-weak) polymorphism for format *) -let warn ?loc = msg Warning ?loc +let warn ?node = msg Warning ?node let warn_noloc ?tags = msg_noloc Warning ?tags -let error ?loc = msg Error ?loc +let error ?node = msg Error ?node let error_noloc ?tags = msg_noloc Error ?tags -let info ?loc = msg Info ?loc +let info ?node = msg Info ?node let info_noloc ?tags = msg_noloc Info ?tags -let debug ?loc = msg Debug ?loc +let debug ?node = msg Debug ?node let debug_noloc ?tags = msg_noloc Debug ?tags -let success ?loc = msg Success ?loc +let success ?node = msg Success ?node let success_noloc ?tags = msg_noloc Success ?tags include Tracing From 79f2956b65c8eb5f6c0ed41d75c1a29b7d1ccd21 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Fri, 14 Jan 2022 12:29:10 +0200 Subject: [PATCH 162/402] Use node instead of loc in spec and fileUse analysis --- src/analyses/fileUse.ml | 4 ++-- src/analyses/spec.ml | 4 ++-- src/cdomains/lvalMapDomain.ml | 22 +++++++++++----------- 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/src/analyses/fileUse.ml b/src/analyses/fileUse.ml index e6faee1ff1..34de7db75d 100644 --- a/src/analyses/fileUse.ml +++ b/src/analyses/fileUse.ml @@ -155,7 +155,7 @@ struct (* M.debug @@ "entering function "^f.vname^string_of_callstack ctx.local; *) let m = if f.svar.vname <> "main" then (* push current location onto stack *) - D.edit_callstack (BatList.cons !Tracing.current_loc) ctx.local + D.edit_callstack (BatList.cons (Option.get !NodeType.current_node)) ctx.local else ctx.local in (* we need to remove all variables that are neither globals nor special variables from the domain for f *) (* problem: we need to be able to check aliases of globals in check_overwrite_open -> keep those in too :/ *) @@ -206,7 +206,7 @@ struct (* is f a pointer to a function we look out for? *) let f = eval_fv (Analyses.ask_of_ctx ctx) (Lval (Var f, NoOffset)) |? f in let m = ctx.local in - let loc = !Tracing.current_loc::(D.callstack m) in + let loc = (Option.get !NodeType.current_node)::(D.callstack m) in let arglist = List.map (Cil.stripCasts) arglist in (* remove casts, TODO safe? *) let split_err_branch lval dom = (* type? NULL = 0 = 0-ptr? Cil.intType, Cil.intPtrType, Cil.voidPtrType -> no difference *) diff --git a/src/analyses/spec.ml b/src/analyses/spec.ml index 304ec90fb2..1837fde549 100644 --- a/src/analyses/spec.ml +++ b/src/analyses/spec.ml @@ -44,7 +44,7 @@ struct struct (* custom goto (D.goto is just for modifying) that checks if the target state is a warning and acts accordingly *) let goto ?may:(may=false) ?change_state:(change_state=true) key state m ws = - let loc = !Tracing.current_loc::(D.callstack m) in + let loc = (Option.get !NodeType.current_node)::(D.callstack m) in let warn key m msg = Str.global_replace (Str.regexp_string "$") (D.string_of_key key) msg |> D.warn ~may:(D.is_may key m || D.is_unknown key m) @@ -419,7 +419,7 @@ struct (* M.debug @@ "entering function "^f.vname^D.string_of_callstack ctx.local; *) if f.svar.vname = "main" then load_specfile (); let m = if f.svar.vname <> "main" then - D.edit_callstack (BatList.cons !Tracing.current_loc) ctx.local + D.edit_callstack (BatList.cons (Option.get !NodeType.current_node)) ctx.local else ctx.local in [m, m] let combine ctx (lval:lval option) fexp (f:fundec) (args:exp list) fc (au:D.t) : D.t = diff --git a/src/cdomains/lvalMapDomain.ml b/src/cdomains/lvalMapDomain.ml index 52875221de..6cead65c54 100644 --- a/src/cdomains/lvalMapDomain.ml +++ b/src/cdomains/lvalMapDomain.ml @@ -21,7 +21,7 @@ sig val string_of_record: r -> string (* constructing *) - val make: k -> location list -> s -> t + val make: k -> Node.t list -> s -> t (* manipulation *) val map: (r -> r) -> t -> t @@ -42,8 +42,8 @@ sig val may: (r -> bool) -> t -> bool (* properties of records *) val key: r -> k - val loc: r -> location list - val edit_loc: (location list -> location list) -> r -> r + val loc: r -> Node.t list + val edit_loc: (Node.t list -> Node.t list) -> r -> r val state: r -> s val in_state: s -> r -> bool @@ -71,14 +71,14 @@ struct type s = Impl.s module R = struct include Printable.Blank - type t = { key: k; loc: location list; state: s } + type t = { key: k; loc: Node.t list; state: s } let hash = Hashtbl.hash - let equal a b = Lval.CilLval.equal a.key b.key && a.loc = b.loc (* FIXME: polymorphic list equal! *) && a.state = b.state + let equal a b = Lval.CilLval.equal a.key b.key && List.equal Node.equal a.loc b.loc && a.state = b.state let compare a b = let r = Lval.CilLval.compare a.key b.key in if r <> 0 then r else - let r = compare a.loc b.loc in (* FIXME: polymorphic list compare! *) + let r = List.compare Node.compare a.loc b.loc in if r <> 0 then r else Impl.compare a.state b.state @@ -104,7 +104,7 @@ struct (* Printing *) let string_of_key k = Lval.CilLval.show k - let string_of_loc xs = String.concat ", " (List.map CilType.Location.show xs) + let string_of_loc xs = String.concat ", " (List.map (CilType.Location.show % Node.location) xs) let string_of_record r = Impl.string_of_state r.state^" ("^string_of_loc r.loc^")" let string_of (x,y) = if is_alias (x,y) then @@ -222,7 +222,7 @@ struct (* callstack for locations *) let callstack_var = Goblintutil.create_var @@ Cil.makeVarinfo false "@callstack" Cil.voidType, `NoOffset let callstack m = get_record callstack_var m |> Option.map_default V.loc [] - let string_of_callstack m = " [call stack: "^String.concat ", " (List.map CilType.Location.show (callstack m))^"]" + let string_of_callstack m = " [call stack: "^String.concat ", " (List.map (CilType.Location.show % Node.location) (callstack m))^"]" let edit_callstack f m = edit_record callstack_var (V.edit_loc f) m @@ -250,12 +250,12 @@ struct let string_of_entry k m = string_of_key k ^ ": " ^ string_of_state k m let string_of_map m = List.map (fun (k,v) -> string_of_entry k m) (bindings m) - let warn ?may:(may=false) ?loc:(loc=[!Tracing.current_loc]) msg = + let warn ?may:(may=false) ?loc:(loc=[Option.get !NodeType.current_node]) msg = match msg |> Str.split (Str.regexp "[ \n\r\x0c\t]+") with - | [] -> (if may then Messages.warn else Messages.error) ~loc:(List.last loc) "%s" msg + | [] -> (if may then Messages.warn else Messages.error) ~node:(List.last loc) "%s" msg | h :: t -> let warn_type = Messages.Category.from_string_list (h |> Str.split (Str.regexp "[.]")) - in (if may then Messages.warn else Messages.error) ~loc:(List.last loc) ~category:warn_type "%a" (Pretty.docList ~sep:(Pretty.text " ") Pretty.text) t + in (if may then Messages.warn else Messages.error) ~node:(List.last loc) ~category:warn_type "%a" (Pretty.docList ~sep:(Pretty.text " ") Pretty.text) t (* getting keys from Cil Lvals *) let sprint f x = Pretty.sprint 80 (f () x) From 4688e9c611ba09bbfea539fc7d8e604e5e707e64 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Fri, 14 Jan 2022 12:31:01 +0200 Subject: [PATCH 163/402] Use node instead of loc in DeadBranchLifter --- src/framework/constraints.ml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/framework/constraints.ml b/src/framework/constraints.ml index 13277d2651..8e3ed8061a 100644 --- a/src/framework/constraints.ml +++ b/src/framework/constraints.ml @@ -1110,7 +1110,7 @@ struct EM.iter (fun exp tv -> match tv with | `Lifted tv -> - M.warn ~loc:(Node.location g) ~tags:[CWE (if tv then 571 else 570)] ~category:Deadcode "condition '%a' is always %B" d_exp exp tv + M.warn ~node:g ~tags:[CWE (if tv then 571 else 570)] ~category:Deadcode "condition '%a' is always %B" d_exp exp tv | `Bot (* all branches dead? can happen at our inserted Neg(1)-s because no Pos(1) *) | `Top -> (* may be both true and false *) () From 999c119c4af839d7539e3d22cf4bfe5b7503f986 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Fri, 14 Jan 2022 12:32:33 +0200 Subject: [PATCH 164/402] Use node instead of loc in uncalled function --- src/framework/control.ml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/framework/control.ml b/src/framework/control.ml index f6ce566bf5..a02989017b 100644 --- a/src/framework/control.ml +++ b/src/framework/control.ml @@ -514,7 +514,7 @@ struct let cnt = Cilfacade.countLoc fn in uncalled_dead := !uncalled_dead + cnt; if get_bool "dbg.uncalled" then - M.warn ~loc ~category:Deadcode "Function \"%a\" will never be called: %dLoC" CilType.Fundec.pretty fn cnt + M.warn ~node:(FunctionEntry fn) ~category:Deadcode "Function \"%a\" will never be called: %dLoC" CilType.Fundec.pretty fn cnt | _ -> () in List.iter print_and_calculate_uncalled file.globals; From bc0bb4b5aba643e176133716b1cd2d4a1129db50 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Fri, 14 Jan 2022 12:33:03 +0200 Subject: [PATCH 165/402] Remove unnecessary current loc from crash and timeout errors --- src/framework/control.ml | 2 +- src/maingoblint.ml | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/framework/control.ml b/src/framework/control.ml index a02989017b..551b32b37b 100644 --- a/src/framework/control.ml +++ b/src/framework/control.ml @@ -574,7 +574,7 @@ struct (* Use "normal" constraint solving *) let timeout_reached () = - M.error ~loc:!Tracing.current_loc "Timeout reached!"; + M.error "Timeout reached!"; (* let module S = Generic.SolverStats (EQSys) (LHT) in *) (* Can't call Generic.SolverStats...print_stats :( print_stats is triggered by dbg.solver-signal, so we send that signal to ourself in maingoblint before re-raising Timeout. diff --git a/src/maingoblint.ml b/src/maingoblint.ml index 8236ca9e04..9eda15daf3 100644 --- a/src/maingoblint.ml +++ b/src/maingoblint.ml @@ -352,8 +352,7 @@ let do_analyze change_info merged_AST = try Control.analyze change_info ast funs with e -> let backtrace = Printexc.get_raw_backtrace () in (* capture backtrace immediately, otherwise the following loses it (internal exception usage without raise_notrace?) *) - let loc = !Tracing.current_loc in - Messages.error ~loc "About to crash!"; (* TODO: move severity coloring to Messages *) + Messages.error "About to crash!"; (* TODO: move severity coloring to Messages *) (* trigger Generic.SolverStats...print_stats *) Goblintutil.(self_signal (signal_of_string (get_string "dbg.solver-signal"))); do_stats (); From 615cb8eff4f66adb449b0615506bc534b7c8b424 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Fri, 14 Jan 2022 13:33:18 +0200 Subject: [PATCH 166/402] Remove loc from message piece --- src/framework/analyses.ml | 7 ++++--- src/framework/node.ml | 11 ----------- src/framework/nodeType.ml | 38 ++++++++++++++++++++++++++++++++++++++ src/util/messages.ml | 17 ++++++++--------- src/util/sarif.ml | 8 ++++---- 5 files changed, 54 insertions(+), 27 deletions(-) diff --git a/src/framework/analyses.ml b/src/framework/analyses.ml index cdc8f3e42d..0dc2eed667 100644 --- a/src/framework/analyses.ml +++ b/src/framework/analyses.ml @@ -166,9 +166,10 @@ struct iter print_one xs let printXmlWarning f () = - let one_text f Messages.Piece.{loc; text = m; _} = - match loc with - | Some l -> + let one_text f Messages.Piece.{node; text = m; _} = + match node with + | Some n -> + let l = Node.location n in BatPrintf.fprintf f "\n%s" l.file l.line l.column (GU.escape m) | None -> () (* TODO: not outputting warning without location *) diff --git a/src/framework/node.ml b/src/framework/node.ml index 4809032a82..62e96cf45a 100644 --- a/src/framework/node.ml +++ b/src/framework/node.ml @@ -46,17 +46,6 @@ let show_cfg = function | FunctionEntry fd -> fd.svar.vname ^ "()" -let hash = function - | Statement stmt -> Hashtbl.hash (CilType.Stmt.hash stmt, 0) - | Function fd -> Hashtbl.hash (CilType.Fundec.hash fd, 1) - | FunctionEntry fd -> Hashtbl.hash (CilType.Fundec.hash fd, 2) - -let location (node: t) = - match node with - | Statement stmt -> Cilfacade.get_stmtLoc stmt - | Function fd -> fd.svar.vdecl - | FunctionEntry fd -> fd.svar.vdecl - (** Find [fundec] which the node is in. In an incremental run this might yield old fundecs for pseudo-return nodes from the old file. *) let find_fundec (node: t) = match node with diff --git a/src/framework/nodeType.ml b/src/framework/nodeType.ml index 1674547fab..ed36d71179 100644 --- a/src/framework/nodeType.ml +++ b/src/framework/nodeType.ml @@ -11,4 +11,42 @@ type t = (** The variable information associated with the function declaration. *) [@@deriving eq, ord, to_yojson] +let hash = function + | Statement stmt -> Hashtbl.hash (CilType.Stmt.hash stmt, 0) + | Function fd -> Hashtbl.hash (CilType.Fundec.hash fd, 1) + | FunctionEntry fd -> Hashtbl.hash (CilType.Fundec.hash fd, 2) + +open Cil +(* TODO: deduplicate with Cilfacade *) +let get_labelLoc = function + | Label (_, loc, _) -> loc + | Case (_, loc, _) -> loc + | CaseRange (_, _, loc, _) -> loc + | Default (loc, _) -> loc + +let rec get_labelsLoc = function + | [] -> Cil.locUnknown + | label :: labels -> + let loc = get_labelLoc label in + if CilType.Location.equal loc Cil.locUnknown then + get_labelsLoc labels (* maybe another label has known location *) + else + loc + +let get_stmtkindLoc = Cil.get_stmtLoc (* CIL has a confusing name for this function *) + +let get_stmtLoc stmt = + match stmt.skind with + (* Cil.get_stmtLoc returns Cil.locUnknown in these cases, so try labels instead *) + | Instr [] + | Block {bstmts = []; _} -> + get_labelsLoc stmt.labels + | _ -> get_stmtkindLoc stmt.skind + +let location (node: t) = + match node with + | Statement stmt -> get_stmtLoc stmt + | Function fd -> fd.svar.vdecl + | FunctionEntry fd -> fd.svar.vdecl + let current_node: t option ref = ref None diff --git a/src/util/messages.ml b/src/util/messages.ml index 11348daf87..ab5606dbf9 100644 --- a/src/util/messages.ml +++ b/src/util/messages.ml @@ -32,14 +32,13 @@ end module Piece = struct type t = { - loc: CilType.Location.t option; (* only *_each warnings have this, used for deduplication *) - node: NodeType.t option; + node: NodeType.t option; (* only *_each warnings have this, used for deduplication *) text: string; context: (Obj.t [@equal fun x y -> Hashtbl.hash (Obj.obj x) = Hashtbl.hash (Obj.obj y)] [@to_yojson fun x -> `Int (Hashtbl.hash (Obj.obj x))]) option; (* TODO: this equality is terrible... *) } [@@deriving eq, to_yojson] - let hash {loc; node; text; context} = - 7 * BatOption.map_default CilType.Location.hash 1 loc + 9 * Hashtbl.hash text + 11 * BatOption.map_default (fun c -> Hashtbl.hash (Obj.obj c)) 1 context (* TODO: use node *) + let hash {node; text; context} = + 7 * BatOption.map_default NodeType.hash 1 node + 9 * Hashtbl.hash text + 11 * BatOption.map_default (fun c -> Hashtbl.hash (Obj.obj c)) 1 context let text_with_context {text; context; _} = match context with @@ -182,7 +181,7 @@ let print ?(ppf= !formatter) (m: Message.t) = let pp_prefix = Format.dprintf "@{<%s>[%a]%a@}" severity_stag Severity.pp m.severity Tags.pp m.tags in let pp_piece ppf piece = let pp_loc ppf = Format.fprintf ppf " @{(%a)@}" CilType.Location.pp in - Format.fprintf ppf "@{<%s>%s@}%a" severity_stag (Piece.text_with_context piece) (Format.pp_print_option pp_loc) piece.loc + Format.fprintf ppf "@{<%s>%s@}%a" severity_stag (Piece.text_with_context piece) (Format.pp_print_option pp_loc) (Option.map NodeType.location piece.node) in let pp_multipiece ppf = match m.multipiece with | Single piece -> @@ -204,7 +203,7 @@ let add m = (** Adapts old [print_group] to new message structure. Don't use for new (group) warnings. *) let msg_group_race_old severity group_name errors = - let m = Message.{tags = [Category Race]; severity; multipiece = Group {group_text = group_name; pieces = List.map (fun (s, loc) -> Piece.{loc = Some loc; node = None; text = s; context = None}) errors}} in (* TODO: use node? *) + let m = Message.{tags = [Category Race]; severity; multipiece = Group {group_text = group_name; pieces = List.map (fun (s, loc) -> Piece.{node = None; text = s; context = None}) errors}} in (* TODO: add node *) add m; if (get_bool "ana.osek.warnfiles") then @@ -233,14 +232,14 @@ let msg severity ?node ?(tags=[]) ?(category=Category.Unknown) fmt = | Some node -> Some node | None -> !NodeType.current_node in - add {tags = Category category :: tags; severity; multipiece = Single {loc = None; node; text; context = msg_context ()}} + add {tags = Category category :: tags; severity; multipiece = Single {node; text; context = msg_context ()}} in Pretty.gprintf finish fmt let msg_noloc severity ?(tags=[]) ?(category=Category.Unknown) fmt = let finish doc = let text = Pretty.sprint ~width:max_int doc in - add {tags = Category category :: tags; severity; multipiece = Single {loc = None; node = None; text; context = msg_context ()}} + add {tags = Category category :: tags; severity; multipiece = Single {node = None; text; context = msg_context ()}} in Pretty.gprintf finish fmt @@ -249,7 +248,7 @@ let msg_group severity ?(tags=[]) ?(category=Category.Unknown) fmt = let group_text = Pretty.sprint ~width:max_int doc in let piece_of_msg (doc, loc) = let text = Pretty.sprint ~width:max_int doc in - Piece.{loc; node = None; text; context = None} (* TODO: add node *) + Piece.{node = None; text; context = None} (* TODO: add node *) in add {tags = Category category :: tags; severity; multipiece = Group {group_text; pieces = List.map piece_of_msg msgs}} in diff --git a/src/util/sarif.ml b/src/util/sarif.ml index 7a154334ea..11eacc4c37 100644 --- a/src/util/sarif.ml +++ b/src/util/sarif.ml @@ -69,8 +69,8 @@ let result_of_message (message: Messages.Message.t): Result.t list = | Debug -> ("informational", "none") | Success -> ("pass", "none") in - let piece_location (piece: Messages.Piece.t) = match piece.loc with - | Some loc -> [location_of_cil_location loc] + let piece_location (piece: Messages.Piece.t) = match piece.node with + | Some node -> [location_of_cil_location (Node.location node)] | None -> [] in let prefix = Format.asprintf "%a " Messages.Tags.pp message.tags in @@ -105,8 +105,8 @@ let result_of_message (message: Messages.Message.t): Result.t list = ) pieces piece_locations let files_of_message (message: Messages.Message.t): string list = - let piece_file (piece: Messages.Piece.t) = match piece.loc with - | Some loc -> Some loc.file + let piece_file (piece: Messages.Piece.t) = match piece.node with + | Some node -> Some (Node.location node).file | None -> None in match message.multipiece with From 2e836670852a8b3c44498faba474299378fe8d72 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Fri, 14 Jan 2022 13:46:55 +0200 Subject: [PATCH 167/402] Generalize message locations to allow CIL locations --- src/framework/analyses.ml | 2 +- src/util/messages.ml | 26 +++++++++++++++++++++++--- src/util/sarif.ml | 4 ++-- 3 files changed, 26 insertions(+), 6 deletions(-) diff --git a/src/framework/analyses.ml b/src/framework/analyses.ml index 0dc2eed667..220dcdd97b 100644 --- a/src/framework/analyses.ml +++ b/src/framework/analyses.ml @@ -169,7 +169,7 @@ struct let one_text f Messages.Piece.{node; text = m; _} = match node with | Some n -> - let l = Node.location n in + let l = Messages.Location.to_cil n in BatPrintf.fprintf f "\n%s" l.file l.line l.column (GU.escape m) | None -> () (* TODO: not outputting warning without location *) diff --git a/src/util/messages.ml b/src/util/messages.ml index ab5606dbf9..99e7945ac2 100644 --- a/src/util/messages.ml +++ b/src/util/messages.ml @@ -29,16 +29,35 @@ struct let to_yojson x = `String (show x) end +module Location = +struct + type t = + | Node of NodeType.t + | CilLocation of CilType.Location.t + [@@deriving eq] + + let hash = function + | Node node -> NodeType.hash node + | CilLocation loc -> CilType.Location.hash loc + + let to_cil = function + | Node node -> NodeType.location node + | CilLocation loc -> loc + + let to_yojson x = CilType.Location.to_yojson (to_cil x) +end + module Piece = struct type t = { - node: NodeType.t option; (* only *_each warnings have this, used for deduplication *) + (* TODO: rename back to loc *) + node: Location.t option; (* only *_each warnings have this, used for deduplication *) text: string; context: (Obj.t [@equal fun x y -> Hashtbl.hash (Obj.obj x) = Hashtbl.hash (Obj.obj y)] [@to_yojson fun x -> `Int (Hashtbl.hash (Obj.obj x))]) option; (* TODO: this equality is terrible... *) } [@@deriving eq, to_yojson] let hash {node; text; context} = - 7 * BatOption.map_default NodeType.hash 1 node + 9 * Hashtbl.hash text + 11 * BatOption.map_default (fun c -> Hashtbl.hash (Obj.obj c)) 1 context + 7 * BatOption.map_default Location.hash 1 node + 9 * Hashtbl.hash text + 11 * BatOption.map_default (fun c -> Hashtbl.hash (Obj.obj c)) 1 context let text_with_context {text; context; _} = match context with @@ -181,7 +200,7 @@ let print ?(ppf= !formatter) (m: Message.t) = let pp_prefix = Format.dprintf "@{<%s>[%a]%a@}" severity_stag Severity.pp m.severity Tags.pp m.tags in let pp_piece ppf piece = let pp_loc ppf = Format.fprintf ppf " @{(%a)@}" CilType.Location.pp in - Format.fprintf ppf "@{<%s>%s@}%a" severity_stag (Piece.text_with_context piece) (Format.pp_print_option pp_loc) (Option.map NodeType.location piece.node) + Format.fprintf ppf "@{<%s>%s@}%a" severity_stag (Piece.text_with_context piece) (Format.pp_print_option pp_loc) (Option.map Location.to_cil piece.node) in let pp_multipiece ppf = match m.multipiece with | Single piece -> @@ -232,6 +251,7 @@ let msg severity ?node ?(tags=[]) ?(category=Category.Unknown) fmt = | Some node -> Some node | None -> !NodeType.current_node in + let node = Option.map (fun node -> Location.Node node) node in add {tags = Category category :: tags; severity; multipiece = Single {node; text; context = msg_context ()}} in Pretty.gprintf finish fmt diff --git a/src/util/sarif.ml b/src/util/sarif.ml index 11eacc4c37..24fd3b88c7 100644 --- a/src/util/sarif.ml +++ b/src/util/sarif.ml @@ -70,7 +70,7 @@ let result_of_message (message: Messages.Message.t): Result.t list = | Success -> ("pass", "none") in let piece_location (piece: Messages.Piece.t) = match piece.node with - | Some node -> [location_of_cil_location (Node.location node)] + | Some node -> [location_of_cil_location (Messages.Location.to_cil node)] | None -> [] in let prefix = Format.asprintf "%a " Messages.Tags.pp message.tags in @@ -106,7 +106,7 @@ let result_of_message (message: Messages.Message.t): Result.t list = let files_of_message (message: Messages.Message.t): string list = let piece_file (piece: Messages.Piece.t) = match piece.node with - | Some node -> Some (Node.location node).file + | Some node -> Some (Messages.Location.to_cil node).file | None -> None in match message.multipiece with From ac2a210d281ec7f965ca36b1d89f37add9223aa0 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Fri, 14 Jan 2022 13:49:56 +0200 Subject: [PATCH 168/402] Readd locations to msg_group --- src/domains/access.ml | 2 +- src/framework/control.ml | 2 +- src/util/messages.ml | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/domains/access.ml b/src/domains/access.ml index f9c2681d76..8351e5c7a1 100644 --- a/src/domains/access.ml +++ b/src/domains/access.ml @@ -480,7 +480,7 @@ let print_accesses (lv, ty) pm = else d_msg () in - (doc, Some loc) + (doc, Some (Messages.Location.CilLocation loc)) (* TODO: use Node *) in AS.elements acs |> List.enum diff --git a/src/framework/control.ml b/src/framework/control.ml index 551b32b37b..1023f5aca3 100644 --- a/src/framework/control.ml +++ b/src/framework/control.ml @@ -126,7 +126,7 @@ struct endByte = 0; (* wrong, but not shown *) } in - (doc, Some loc) + (doc, Some (Messages.Location.CilLocation loc)) in let msgs = BatISet.fold_range (fun b e acc -> diff --git a/src/util/messages.ml b/src/util/messages.ml index 99e7945ac2..a9015ee94d 100644 --- a/src/util/messages.ml +++ b/src/util/messages.ml @@ -222,7 +222,7 @@ let add m = (** Adapts old [print_group] to new message structure. Don't use for new (group) warnings. *) let msg_group_race_old severity group_name errors = - let m = Message.{tags = [Category Race]; severity; multipiece = Group {group_text = group_name; pieces = List.map (fun (s, loc) -> Piece.{node = None; text = s; context = None}) errors}} in (* TODO: add node *) + let m = Message.{tags = [Category Race]; severity; multipiece = Group {group_text = group_name; pieces = List.map (fun (s, loc) -> Piece.{node = Some (CilLocation loc); text = s; context = None}) errors}} in add m; if (get_bool "ana.osek.warnfiles") then @@ -268,7 +268,7 @@ let msg_group severity ?(tags=[]) ?(category=Category.Unknown) fmt = let group_text = Pretty.sprint ~width:max_int doc in let piece_of_msg (doc, loc) = let text = Pretty.sprint ~width:max_int doc in - Piece.{node = None; text; context = None} (* TODO: add node *) + Piece.{node = loc; text; context = None} (* TODO: add node *) in add {tags = Category category :: tags; severity; multipiece = Group {group_text; pieces = List.map piece_of_msg msgs}} in From 8ac2ac402800456ac93abe50230e888df11d9d97 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Fri, 14 Jan 2022 14:07:14 +0200 Subject: [PATCH 169/402] Rename message node back to loc --- src/analyses/deadlock.ml | 2 +- src/cdomains/lvalMapDomain.ml | 4 ++-- src/framework/analyses.ml | 8 ++++---- src/framework/constraints.ml | 2 +- src/framework/control.ml | 2 +- src/util/messages.ml | 34 ++++++++++++++++------------------ src/util/sarif.ml | 8 ++++---- 7 files changed, 29 insertions(+), 31 deletions(-) diff --git a/src/analyses/deadlock.ml b/src/analyses/deadlock.ml index 6de7c9564f..09719a802a 100644 --- a/src/analyses/deadlock.ml +++ b/src/analyses/deadlock.ml @@ -27,7 +27,7 @@ struct D.iter (fun e -> List.iter (fun (a,b) -> if ((MyLock.equal a e) && (MyLock.equal b newLock)) then ( Messages.warn "Deadlock warning: Locking order %a, %a at %a, %a violates order at %a, %a." ValueDomain.Addr.pretty e.addr ValueDomain.Addr.pretty newLock.addr CilType.Location.pretty (Node.location e.node) CilType.Location.pretty (Node.location newLock.node) CilType.Location.pretty (Node.location b.node) CilType.Location.pretty (Node.location a.node); - Messages.warn ~node:a.node "Deadlock warning: Locking order %a, %a at %a, %a violates order at %a, %a." ValueDomain.Addr.pretty newLock.addr ValueDomain.Addr.pretty e.addr CilType.Location.pretty (Node.location b.node) CilType.Location.pretty (Node.location a.node) CilType.Location.pretty (Node.location e.node) CilType.Location.pretty (Node.location newLock.node); + Messages.warn ~loc:(Node a.node) "Deadlock warning: Locking order %a, %a at %a, %a violates order at %a, %a." ValueDomain.Addr.pretty newLock.addr ValueDomain.Addr.pretty e.addr CilType.Location.pretty (Node.location b.node) CilType.Location.pretty (Node.location a.node) CilType.Location.pretty (Node.location e.node) CilType.Location.pretty (Node.location newLock.node); ) else () ) !forbiddenList ) lockList; diff --git a/src/cdomains/lvalMapDomain.ml b/src/cdomains/lvalMapDomain.ml index 6cead65c54..c106a4974a 100644 --- a/src/cdomains/lvalMapDomain.ml +++ b/src/cdomains/lvalMapDomain.ml @@ -252,10 +252,10 @@ struct let warn ?may:(may=false) ?loc:(loc=[Option.get !NodeType.current_node]) msg = match msg |> Str.split (Str.regexp "[ \n\r\x0c\t]+") with - | [] -> (if may then Messages.warn else Messages.error) ~node:(List.last loc) "%s" msg + | [] -> (if may then Messages.warn else Messages.error) ~loc:(Node (List.last loc)) "%s" msg | h :: t -> let warn_type = Messages.Category.from_string_list (h |> Str.split (Str.regexp "[.]")) - in (if may then Messages.warn else Messages.error) ~node:(List.last loc) ~category:warn_type "%a" (Pretty.docList ~sep:(Pretty.text " ") Pretty.text) t + in (if may then Messages.warn else Messages.error) ~loc:(Node (List.last loc)) ~category:warn_type "%a" (Pretty.docList ~sep:(Pretty.text " ") Pretty.text) t (* getting keys from Cil Lvals *) let sprint f x = Pretty.sprint 80 (f () x) diff --git a/src/framework/analyses.ml b/src/framework/analyses.ml index 220dcdd97b..88bb355da2 100644 --- a/src/framework/analyses.ml +++ b/src/framework/analyses.ml @@ -166,10 +166,10 @@ struct iter print_one xs let printXmlWarning f () = - let one_text f Messages.Piece.{node; text = m; _} = - match node with - | Some n -> - let l = Messages.Location.to_cil n in + let one_text f Messages.Piece.{loc; text = m; _} = + match loc with + | Some loc -> + let l = Messages.Location.to_cil loc in BatPrintf.fprintf f "\n%s" l.file l.line l.column (GU.escape m) | None -> () (* TODO: not outputting warning without location *) diff --git a/src/framework/constraints.ml b/src/framework/constraints.ml index 8e3ed8061a..f1dd34ac5b 100644 --- a/src/framework/constraints.ml +++ b/src/framework/constraints.ml @@ -1110,7 +1110,7 @@ struct EM.iter (fun exp tv -> match tv with | `Lifted tv -> - M.warn ~node:g ~tags:[CWE (if tv then 571 else 570)] ~category:Deadcode "condition '%a' is always %B" d_exp exp tv + M.warn ~loc:(Node g) ~tags:[CWE (if tv then 571 else 570)] ~category:Deadcode "condition '%a' is always %B" d_exp exp tv | `Bot (* all branches dead? can happen at our inserted Neg(1)-s because no Pos(1) *) | `Top -> (* may be both true and false *) () diff --git a/src/framework/control.ml b/src/framework/control.ml index 1023f5aca3..c48e3791af 100644 --- a/src/framework/control.ml +++ b/src/framework/control.ml @@ -514,7 +514,7 @@ struct let cnt = Cilfacade.countLoc fn in uncalled_dead := !uncalled_dead + cnt; if get_bool "dbg.uncalled" then - M.warn ~node:(FunctionEntry fn) ~category:Deadcode "Function \"%a\" will never be called: %dLoC" CilType.Fundec.pretty fn cnt + M.warn ~loc:(CilLocation loc) ~category:Deadcode "Function \"%a\" will never be called: %dLoC" CilType.Fundec.pretty fn cnt | _ -> () in List.iter print_and_calculate_uncalled file.globals; diff --git a/src/util/messages.ml b/src/util/messages.ml index a9015ee94d..efde73222b 100644 --- a/src/util/messages.ml +++ b/src/util/messages.ml @@ -50,14 +50,13 @@ end module Piece = struct type t = { - (* TODO: rename back to loc *) - node: Location.t option; (* only *_each warnings have this, used for deduplication *) + loc: Location.t option; (* only *_each warnings have this, used for deduplication *) text: string; context: (Obj.t [@equal fun x y -> Hashtbl.hash (Obj.obj x) = Hashtbl.hash (Obj.obj y)] [@to_yojson fun x -> `Int (Hashtbl.hash (Obj.obj x))]) option; (* TODO: this equality is terrible... *) } [@@deriving eq, to_yojson] - let hash {node; text; context} = - 7 * BatOption.map_default Location.hash 1 node + 9 * Hashtbl.hash text + 11 * BatOption.map_default (fun c -> Hashtbl.hash (Obj.obj c)) 1 context + let hash {loc; text; context} = + 7 * BatOption.map_default Location.hash 1 loc + 9 * Hashtbl.hash text + 11 * BatOption.map_default (fun c -> Hashtbl.hash (Obj.obj c)) 1 context let text_with_context {text; context; _} = match context with @@ -200,7 +199,7 @@ let print ?(ppf= !formatter) (m: Message.t) = let pp_prefix = Format.dprintf "@{<%s>[%a]%a@}" severity_stag Severity.pp m.severity Tags.pp m.tags in let pp_piece ppf piece = let pp_loc ppf = Format.fprintf ppf " @{(%a)@}" CilType.Location.pp in - Format.fprintf ppf "@{<%s>%s@}%a" severity_stag (Piece.text_with_context piece) (Format.pp_print_option pp_loc) (Option.map Location.to_cil piece.node) + Format.fprintf ppf "@{<%s>%s@}%a" severity_stag (Piece.text_with_context piece) (Format.pp_print_option pp_loc) (Option.map Location.to_cil piece.loc) in let pp_multipiece ppf = match m.multipiece with | Single piece -> @@ -222,7 +221,7 @@ let add m = (** Adapts old [print_group] to new message structure. Don't use for new (group) warnings. *) let msg_group_race_old severity group_name errors = - let m = Message.{tags = [Category Race]; severity; multipiece = Group {group_text = group_name; pieces = List.map (fun (s, loc) -> Piece.{node = Some (CilLocation loc); text = s; context = None}) errors}} in + let m = Message.{tags = [Category Race]; severity; multipiece = Group {group_text = group_name; pieces = List.map (fun (s, loc) -> Piece.{loc = Some (CilLocation loc); text = s; context = None}) errors}} in add m; if (get_bool "ana.osek.warnfiles") then @@ -244,22 +243,21 @@ let msg_context () = else None (* avoid identical messages from multiple contexts without any mention of context *) -let msg severity ?node ?(tags=[]) ?(category=Category.Unknown) fmt = +let msg severity ?loc ?(tags=[]) ?(category=Category.Unknown) fmt = let finish doc = let text = Pretty.sprint ~width:max_int doc in - let node = match node with + let loc = match loc with | Some node -> Some node - | None -> !NodeType.current_node + | None -> Option.map (fun node -> Location.Node node) !NodeType.current_node in - let node = Option.map (fun node -> Location.Node node) node in - add {tags = Category category :: tags; severity; multipiece = Single {node; text; context = msg_context ()}} + add {tags = Category category :: tags; severity; multipiece = Single {loc; text; context = msg_context ()}} in Pretty.gprintf finish fmt let msg_noloc severity ?(tags=[]) ?(category=Category.Unknown) fmt = let finish doc = let text = Pretty.sprint ~width:max_int doc in - add {tags = Category category :: tags; severity; multipiece = Single {node = None; text; context = msg_context ()}} + add {tags = Category category :: tags; severity; multipiece = Single {loc = None; text; context = msg_context ()}} in Pretty.gprintf finish fmt @@ -268,22 +266,22 @@ let msg_group severity ?(tags=[]) ?(category=Category.Unknown) fmt = let group_text = Pretty.sprint ~width:max_int doc in let piece_of_msg (doc, loc) = let text = Pretty.sprint ~width:max_int doc in - Piece.{node = loc; text; context = None} (* TODO: add node *) + Piece.{loc; text; context = None} in add {tags = Category category :: tags; severity; multipiece = Group {group_text; pieces = List.map piece_of_msg msgs}} in Pretty.gprintf finish fmt (* must eta-expand to get proper (non-weak) polymorphism for format *) -let warn ?node = msg Warning ?node +let warn ?loc = msg Warning ?loc let warn_noloc ?tags = msg_noloc Warning ?tags -let error ?node = msg Error ?node +let error ?loc = msg Error ?loc let error_noloc ?tags = msg_noloc Error ?tags -let info ?node = msg Info ?node +let info ?loc = msg Info ?loc let info_noloc ?tags = msg_noloc Info ?tags -let debug ?node = msg Debug ?node +let debug ?loc = msg Debug ?loc let debug_noloc ?tags = msg_noloc Debug ?tags -let success ?node = msg Success ?node +let success ?loc = msg Success ?loc let success_noloc ?tags = msg_noloc Success ?tags include Tracing diff --git a/src/util/sarif.ml b/src/util/sarif.ml index 24fd3b88c7..fa48a7b1ed 100644 --- a/src/util/sarif.ml +++ b/src/util/sarif.ml @@ -69,8 +69,8 @@ let result_of_message (message: Messages.Message.t): Result.t list = | Debug -> ("informational", "none") | Success -> ("pass", "none") in - let piece_location (piece: Messages.Piece.t) = match piece.node with - | Some node -> [location_of_cil_location (Messages.Location.to_cil node)] + let piece_location (piece: Messages.Piece.t) = match piece.loc with + | Some loc -> [location_of_cil_location (Messages.Location.to_cil loc)] | None -> [] in let prefix = Format.asprintf "%a " Messages.Tags.pp message.tags in @@ -105,8 +105,8 @@ let result_of_message (message: Messages.Message.t): Result.t list = ) pieces piece_locations let files_of_message (message: Messages.Message.t): string list = - let piece_file (piece: Messages.Piece.t) = match piece.node with - | Some node -> Some (Messages.Location.to_cil node).file + let piece_file (piece: Messages.Piece.t) = match piece.loc with + | Some loc -> Some (Messages.Location.to_cil loc).file | None -> None in match message.multipiece with From 8a64dc40e57f43c4966ea3f4d769a95e2606678e Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Fri, 14 Jan 2022 14:22:36 +0200 Subject: [PATCH 170/402] Simplify deadlock location printing --- src/analyses/deadlock.ml | 4 ++-- src/cdomains/deadlockDomain.ml | 5 +++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/analyses/deadlock.ml b/src/analyses/deadlock.ml index 09719a802a..ad743220ed 100644 --- a/src/analyses/deadlock.ml +++ b/src/analyses/deadlock.ml @@ -26,8 +26,8 @@ struct if !Goblintutil.postsolving then begin D.iter (fun e -> List.iter (fun (a,b) -> if ((MyLock.equal a e) && (MyLock.equal b newLock)) then ( - Messages.warn "Deadlock warning: Locking order %a, %a at %a, %a violates order at %a, %a." ValueDomain.Addr.pretty e.addr ValueDomain.Addr.pretty newLock.addr CilType.Location.pretty (Node.location e.node) CilType.Location.pretty (Node.location newLock.node) CilType.Location.pretty (Node.location b.node) CilType.Location.pretty (Node.location a.node); - Messages.warn ~loc:(Node a.node) "Deadlock warning: Locking order %a, %a at %a, %a violates order at %a, %a." ValueDomain.Addr.pretty newLock.addr ValueDomain.Addr.pretty e.addr CilType.Location.pretty (Node.location b.node) CilType.Location.pretty (Node.location a.node) CilType.Location.pretty (Node.location e.node) CilType.Location.pretty (Node.location newLock.node); + Messages.warn "Deadlock warning: Locking order %a, %a at %a, %a violates order at %a, %a." ValueDomain.Addr.pretty e.addr ValueDomain.Addr.pretty newLock.addr pretty_node_loc e.node pretty_node_loc newLock.node pretty_node_loc b.node pretty_node_loc a.node; + Messages.warn ~loc:(Node a.node) "Deadlock warning: Locking order %a, %a at %a, %a violates order at %a, %a." ValueDomain.Addr.pretty newLock.addr ValueDomain.Addr.pretty e.addr pretty_node_loc b.node pretty_node_loc a.node pretty_node_loc e.node pretty_node_loc newLock.node; ) else () ) !forbiddenList ) lockList; diff --git a/src/cdomains/deadlockDomain.ml b/src/cdomains/deadlockDomain.ml index 8136b167db..fb0a532a43 100644 --- a/src/cdomains/deadlockDomain.ml +++ b/src/cdomains/deadlockDomain.ml @@ -1,8 +1,9 @@ -open Cil open Pretty type myowntypeEntry = {addr : ValueDomain.Addr.t ; node : Node.t} +let pretty_node_loc () node = CilType.Location.pretty () (Node.location node) + module MyLock : Printable.S with type t = myowntypeEntry = struct @@ -16,7 +17,7 @@ struct let compare x y = Ad.compare x.addr y.addr (* ignores loc field *) (* TODO: deadlock analysis output doesn't even use these, but manually outputs locations *) let show x = (Ad.show x.addr) ^ "@" ^ (CilType.Location.show (Node.location x.node)) - let pretty () x = Ad.pretty () x.addr ++ text "@" ++ CilType.Location.pretty () (Node.location x.node) + let pretty () x = Ad.pretty () x.addr ++ text "@" ++ pretty_node_loc () x.node let printXml c x = Ad.printXml c x.addr let to_yojson x = `String (show x) end From ed6847b80df9ba009f7777ca477bde0a135869dc Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Fri, 14 Jan 2022 14:28:18 +0200 Subject: [PATCH 171/402] Use node instead of loc for accesses --- src/domains/access.ml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/domains/access.ml b/src/domains/access.ml index 8351e5c7a1..91eeddc5fc 100644 --- a/src/domains/access.ml +++ b/src/domains/access.ml @@ -211,7 +211,7 @@ let get_val_type e (vo: var_o) (oo: off_o) : acc_typ = let add_one side (e:exp) (w:bool) (conf:int) (ty:acc_typ) (lv:(varinfo*offs) option) ((pp,lp):part): unit = if is_ignorable lv then () else begin - let loc = !Tracing.current_loc in + let loc = Option.get !Node.current_node in let add_part ls = side ty lv (Some ls) (conf, w, loc, e, lp) in @@ -374,12 +374,12 @@ let add side e w conf vo oo p = module A = struct include Printable.Std - type t = int * bool * CilType.Location.t * CilType.Exp.t * LSSet.t [@@deriving eq, ord] + type t = int * bool * Node.t * CilType.Exp.t * LSSet.t [@@deriving eq, ord] let hash (conf, w, loc, e, lp) = 0 (* TODO: never hashed? *) - let pretty () (conf, w, loc, e, lp) = - Pretty.dprintf "%d, %B, %a, %a, %a" conf w CilType.Location.pretty loc CilType.Exp.pretty e LSSet.pretty lp + let pretty () (conf, w, node, e, lp) = + Pretty.dprintf "%d, %B, %a, %a, %a" conf w CilType.Location.pretty (Node.location node) CilType.Exp.pretty e LSSet.pretty lp let show x = Pretty.sprint ~width:max_int (pretty () x) let printXml f x = BatPrintf.fprintf f "\n\n%s\n\n\n" (XmlUtil.escape (show x)) @@ -466,7 +466,7 @@ let print_accesses (lv, ty) pm = let allglobs = get_bool "allglobs" in let debug = get_bool "dbg.debug" in let g (ls, acs) = - let h (conf,w,loc,e,lp) = + let h (conf,w,node,e,lp) = let d_ls () = match ls with | None -> Pretty.text " is ok" (* None is used by add_one when access partitions set is empty (not singleton), so access is considered unracing (single-threaded or bullet region)*) | Some ls when LSSet.is_empty ls -> nil @@ -480,7 +480,7 @@ let print_accesses (lv, ty) pm = else d_msg () in - (doc, Some (Messages.Location.CilLocation loc)) (* TODO: use Node *) + (doc, Some (Messages.Location.Node node)) in AS.elements acs |> List.enum From 8d6aa25840ee7031f70281f2c13975357b188cd4 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Fri, 14 Jan 2022 14:44:42 +0200 Subject: [PATCH 172/402] Deduplicate Cilfacade --- src/analyses/deadlock.ml | 4 ++-- src/analyses/fileUse.ml | 4 ++-- src/analyses/spec.ml | 4 ++-- src/cdomains/lvalMapDomain.ml | 2 +- src/framework/node.ml | 2 +- src/framework/{nodeType.ml => node0.ml} | 31 +++---------------------- src/util/cilfacade.ml | 27 +-------------------- src/util/cilfacade0.ml | 27 +++++++++++++++++++++ src/util/messages.ml | 8 +++---- 9 files changed, 43 insertions(+), 66 deletions(-) rename src/framework/{nodeType.ml => node0.ml} (55%) create mode 100644 src/util/cilfacade0.ml diff --git a/src/analyses/deadlock.ml b/src/analyses/deadlock.ml index ad743220ed..0dc769025a 100644 --- a/src/analyses/deadlock.ml +++ b/src/analyses/deadlock.ml @@ -96,8 +96,8 @@ struct match LibraryFunctions.classify f.vname arglist with | `Lock (_, _, _) -> List.fold_left (fun d lockAddr -> - addLockingInfo {addr = lockAddr; node = Option.get !NodeType.current_node } ctx.local; - D.add {addr = lockAddr; node = Option.get !NodeType.current_node } ctx.local + addLockingInfo {addr = lockAddr; node = Option.get !Node.current_node } ctx.local; + D.add {addr = lockAddr; node = Option.get !Node.current_node } ctx.local ) ctx.local (eval_exp_addr (Analyses.ask_of_ctx ctx) (List.hd arglist)) | `Unlock -> let lockAddrs = eval_exp_addr (Analyses.ask_of_ctx ctx) (List.hd arglist) in diff --git a/src/analyses/fileUse.ml b/src/analyses/fileUse.ml index 34de7db75d..dbb57e801b 100644 --- a/src/analyses/fileUse.ml +++ b/src/analyses/fileUse.ml @@ -155,7 +155,7 @@ struct (* M.debug @@ "entering function "^f.vname^string_of_callstack ctx.local; *) let m = if f.svar.vname <> "main" then (* push current location onto stack *) - D.edit_callstack (BatList.cons (Option.get !NodeType.current_node)) ctx.local + D.edit_callstack (BatList.cons (Option.get !Node.current_node)) ctx.local else ctx.local in (* we need to remove all variables that are neither globals nor special variables from the domain for f *) (* problem: we need to be able to check aliases of globals in check_overwrite_open -> keep those in too :/ *) @@ -206,7 +206,7 @@ struct (* is f a pointer to a function we look out for? *) let f = eval_fv (Analyses.ask_of_ctx ctx) (Lval (Var f, NoOffset)) |? f in let m = ctx.local in - let loc = (Option.get !NodeType.current_node)::(D.callstack m) in + let loc = (Option.get !Node.current_node)::(D.callstack m) in let arglist = List.map (Cil.stripCasts) arglist in (* remove casts, TODO safe? *) let split_err_branch lval dom = (* type? NULL = 0 = 0-ptr? Cil.intType, Cil.intPtrType, Cil.voidPtrType -> no difference *) diff --git a/src/analyses/spec.ml b/src/analyses/spec.ml index 1837fde549..52c4a86fcb 100644 --- a/src/analyses/spec.ml +++ b/src/analyses/spec.ml @@ -44,7 +44,7 @@ struct struct (* custom goto (D.goto is just for modifying) that checks if the target state is a warning and acts accordingly *) let goto ?may:(may=false) ?change_state:(change_state=true) key state m ws = - let loc = (Option.get !NodeType.current_node)::(D.callstack m) in + let loc = (Option.get !Node.current_node)::(D.callstack m) in let warn key m msg = Str.global_replace (Str.regexp_string "$") (D.string_of_key key) msg |> D.warn ~may:(D.is_may key m || D.is_unknown key m) @@ -419,7 +419,7 @@ struct (* M.debug @@ "entering function "^f.vname^D.string_of_callstack ctx.local; *) if f.svar.vname = "main" then load_specfile (); let m = if f.svar.vname <> "main" then - D.edit_callstack (BatList.cons (Option.get !NodeType.current_node)) ctx.local + D.edit_callstack (BatList.cons (Option.get !Node.current_node)) ctx.local else ctx.local in [m, m] let combine ctx (lval:lval option) fexp (f:fundec) (args:exp list) fc (au:D.t) : D.t = diff --git a/src/cdomains/lvalMapDomain.ml b/src/cdomains/lvalMapDomain.ml index c106a4974a..4ed0d9b703 100644 --- a/src/cdomains/lvalMapDomain.ml +++ b/src/cdomains/lvalMapDomain.ml @@ -250,7 +250,7 @@ struct let string_of_entry k m = string_of_key k ^ ": " ^ string_of_state k m let string_of_map m = List.map (fun (k,v) -> string_of_entry k m) (bindings m) - let warn ?may:(may=false) ?loc:(loc=[Option.get !NodeType.current_node]) msg = + let warn ?may:(may=false) ?loc:(loc=[Option.get !Node.current_node]) msg = match msg |> Str.split (Str.regexp "[ \n\r\x0c\t]+") with | [] -> (if may then Messages.warn else Messages.error) ~loc:(Node (List.last loc)) "%s" msg | h :: t -> diff --git a/src/framework/node.ml b/src/framework/node.ml index 62e96cf45a..5ce1106eff 100644 --- a/src/framework/node.ml +++ b/src/framework/node.ml @@ -3,7 +3,7 @@ open Pretty include Printable.Std -include NodeType +include Node0 let name () = "node" diff --git a/src/framework/nodeType.ml b/src/framework/node0.ml similarity index 55% rename from src/framework/nodeType.ml rename to src/framework/node0.ml index ed36d71179..749b697e64 100644 --- a/src/framework/nodeType.ml +++ b/src/framework/node0.ml @@ -1,3 +1,5 @@ +(** Node functions to avoid dependency cycles. *) + (** A node in the Control Flow Graph is either a statement or function. Think of * the function node as last node that all the returning nodes point to. So * the result of the function call is contained in the function node. *) @@ -16,36 +18,9 @@ let hash = function | Function fd -> Hashtbl.hash (CilType.Fundec.hash fd, 1) | FunctionEntry fd -> Hashtbl.hash (CilType.Fundec.hash fd, 2) -open Cil -(* TODO: deduplicate with Cilfacade *) -let get_labelLoc = function - | Label (_, loc, _) -> loc - | Case (_, loc, _) -> loc - | CaseRange (_, _, loc, _) -> loc - | Default (loc, _) -> loc - -let rec get_labelsLoc = function - | [] -> Cil.locUnknown - | label :: labels -> - let loc = get_labelLoc label in - if CilType.Location.equal loc Cil.locUnknown then - get_labelsLoc labels (* maybe another label has known location *) - else - loc - -let get_stmtkindLoc = Cil.get_stmtLoc (* CIL has a confusing name for this function *) - -let get_stmtLoc stmt = - match stmt.skind with - (* Cil.get_stmtLoc returns Cil.locUnknown in these cases, so try labels instead *) - | Instr [] - | Block {bstmts = []; _} -> - get_labelsLoc stmt.labels - | _ -> get_stmtkindLoc stmt.skind - let location (node: t) = match node with - | Statement stmt -> get_stmtLoc stmt + | Statement stmt -> Cilfacade0.get_stmtLoc stmt | Function fd -> fd.svar.vdecl | FunctionEntry fd -> fd.svar.vdecl diff --git a/src/util/cilfacade.ml b/src/util/cilfacade.ml index daed6a4822..09e2199890 100644 --- a/src/util/cilfacade.ml +++ b/src/util/cilfacade.ml @@ -5,32 +5,7 @@ open Cil module E = Errormsg module GU = Goblintutil - -let get_labelLoc = function - | Label (_, loc, _) -> loc - | Case (_, loc, _) -> loc - | CaseRange (_, _, loc, _) -> loc - | Default (loc, _) -> loc - -let rec get_labelsLoc = function - | [] -> Cil.locUnknown - | label :: labels -> - let loc = get_labelLoc label in - if CilType.Location.equal loc Cil.locUnknown then - get_labelsLoc labels (* maybe another label has known location *) - else - loc - -let get_stmtkindLoc = Cil.get_stmtLoc (* CIL has a confusing name for this function *) - -let get_stmtLoc stmt = - match stmt.skind with - (* Cil.get_stmtLoc returns Cil.locUnknown in these cases, so try labels instead *) - | Instr [] - | Block {bstmts = []; _} -> - get_labelsLoc stmt.labels - | _ -> get_stmtkindLoc stmt.skind - +include Cilfacade0 let init () = initCIL (); diff --git a/src/util/cilfacade0.ml b/src/util/cilfacade0.ml new file mode 100644 index 0000000000..dfe6dd031b --- /dev/null +++ b/src/util/cilfacade0.ml @@ -0,0 +1,27 @@ +(** Cilfacade functions to avoid dependency cycles.*) +open Cil + +let get_labelLoc = function + | Label (_, loc, _) -> loc + | Case (_, loc, _) -> loc + | CaseRange (_, _, loc, _) -> loc + | Default (loc, _) -> loc + +let rec get_labelsLoc = function + | [] -> Cil.locUnknown + | label :: labels -> + let loc = get_labelLoc label in + if CilType.Location.equal loc Cil.locUnknown then + get_labelsLoc labels (* maybe another label has known location *) + else + loc + +let get_stmtkindLoc = Cil.get_stmtLoc (* CIL has a confusing name for this function *) + +let get_stmtLoc stmt = + match stmt.skind with + (* Cil.get_stmtLoc returns Cil.locUnknown in these cases, so try labels instead *) + | Instr [] + | Block {bstmts = []; _} -> + get_labelsLoc stmt.labels + | _ -> get_stmtkindLoc stmt.skind diff --git a/src/util/messages.ml b/src/util/messages.ml index efde73222b..a75073b94b 100644 --- a/src/util/messages.ml +++ b/src/util/messages.ml @@ -32,16 +32,16 @@ end module Location = struct type t = - | Node of NodeType.t + | Node of Node0.t | CilLocation of CilType.Location.t [@@deriving eq] let hash = function - | Node node -> NodeType.hash node + | Node node -> Node0.hash node | CilLocation loc -> CilType.Location.hash loc let to_cil = function - | Node node -> NodeType.location node + | Node node -> Node0.location node | CilLocation loc -> loc let to_yojson x = CilType.Location.to_yojson (to_cil x) @@ -248,7 +248,7 @@ let msg severity ?loc ?(tags=[]) ?(category=Category.Unknown) fmt = let text = Pretty.sprint ~width:max_int doc in let loc = match loc with | Some node -> Some node - | None -> Option.map (fun node -> Location.Node node) !NodeType.current_node + | None -> Option.map (fun node -> Location.Node node) !Node0.current_node in add {tags = Category category :: tags; severity; multipiece = Single {loc; text; context = msg_context ()}} in From 1a3f429336d914544f82a6a8c6ba633fbd800bc7 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Fri, 14 Jan 2022 14:46:02 +0200 Subject: [PATCH 173/402] Exclude Cilfacade0 from semgrep --- .semgrep/cil.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.semgrep/cil.yml b/.semgrep/cil.yml index 20e75018ce..7cc2e78f40 100644 --- a/.semgrep/cil.yml +++ b/.semgrep/cil.yml @@ -8,6 +8,7 @@ rules: - pattern: Cil.get_stmtLoc paths: exclude: + - cilfacade0.ml - cilfacade.ml message: use Cilfacade instead languages: [ocaml] From a7145204c6efe2f692c934182524df8ea523a1c6 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Fri, 14 Jan 2022 15:06:18 +0200 Subject: [PATCH 174/402] Use incremental locations for message output --- src/incremental/updateCil.ml | 14 +------------- src/incremental/updateCil0.ml | 15 +++++++++++++++ src/util/messages.ml | 2 +- 3 files changed, 17 insertions(+), 14 deletions(-) create mode 100644 src/incremental/updateCil0.ml diff --git a/src/incremental/updateCil.ml b/src/incremental/updateCil.ml index c827ce66f0..ea9e10219c 100644 --- a/src/incremental/updateCil.ml +++ b/src/incremental/updateCil.ml @@ -3,19 +3,7 @@ open CompareCIL open VersionLookup open MyCFG -module NodeMap = Hashtbl.Make(Node) - -let location_map = ref (NodeMap.create 103: location NodeMap.t) - -let getLoc (node: Node.t) = - (* In case this belongs to a changed function, we will find the true location in the map*) - try - NodeMap.find !location_map node - with Not_found -> - Node.location node - -let store_node_location (n: Node.t) (l: location): unit = - NodeMap.add !location_map n l +include UpdateCil0 let update_ids (old_file: file) (ids: max_ids) (new_file: file) (map: (global_identifier, Cil.global) Hashtbl.t) (changes: change_info) = let vid_max = ref ids.max_vid in diff --git a/src/incremental/updateCil0.ml b/src/incremental/updateCil0.ml new file mode 100644 index 0000000000..7a929d1883 --- /dev/null +++ b/src/incremental/updateCil0.ml @@ -0,0 +1,15 @@ +(** UpdateCil functions to avoid dependency cycles.*) + +module NodeMap = Hashtbl.Make(Node0) + +let location_map = ref (NodeMap.create 103: Cil.location NodeMap.t) + +let getLoc (node: Node0.t) = + (* In case this belongs to a changed function, we will find the true location in the map*) + try + NodeMap.find !location_map node + with Not_found -> + Node0.location node + +let store_node_location (n: Node0.t) (l: Cil.location): unit = + NodeMap.add !location_map n l diff --git a/src/util/messages.ml b/src/util/messages.ml index a75073b94b..3ebd82183f 100644 --- a/src/util/messages.ml +++ b/src/util/messages.ml @@ -41,7 +41,7 @@ struct | CilLocation loc -> CilType.Location.hash loc let to_cil = function - | Node node -> Node0.location node + | Node node -> UpdateCil0.getLoc node | CilLocation loc -> loc let to_yojson x = CilType.Location.to_yojson (to_cil x) From f4a07d70dfbf601e325c910439cfc1750c010264 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Fri, 14 Jan 2022 15:14:52 +0200 Subject: [PATCH 175/402] Document message locations --- src/framework/control.ml | 4 ++-- src/util/messages.ml | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/framework/control.ml b/src/framework/control.ml index c48e3791af..223dbc3782 100644 --- a/src/framework/control.ml +++ b/src/framework/control.ml @@ -126,7 +126,7 @@ struct endByte = 0; (* wrong, but not shown *) } in - (doc, Some (Messages.Location.CilLocation loc)) + (doc, Some (Messages.Location.CilLocation loc)) (* CilLocation is fine because always printed from scratch *) in let msgs = BatISet.fold_range (fun b e acc -> @@ -514,7 +514,7 @@ struct let cnt = Cilfacade.countLoc fn in uncalled_dead := !uncalled_dead + cnt; if get_bool "dbg.uncalled" then - M.warn ~loc:(CilLocation loc) ~category:Deadcode "Function \"%a\" will never be called: %dLoC" CilType.Fundec.pretty fn cnt + M.warn ~loc:(CilLocation loc) ~category:Deadcode "Function \"%a\" will never be called: %dLoC" CilType.Fundec.pretty fn cnt (* CilLocation is fine because always printed from scratch *) | _ -> () in List.iter print_and_calculate_uncalled file.globals; diff --git a/src/util/messages.ml b/src/util/messages.ml index 3ebd82183f..aa5544c37d 100644 --- a/src/util/messages.ml +++ b/src/util/messages.ml @@ -32,8 +32,8 @@ end module Location = struct type t = - | Node of Node0.t - | CilLocation of CilType.Location.t + | Node of Node0.t (** Location identified by a node. Strongly preferred, because output location updates incrementally. *) + | CilLocation of CilType.Location.t (** Location identified by a literal CIL location. Strongly discouraged, because not updated incrementally. *) [@@deriving eq] let hash = function @@ -41,7 +41,7 @@ struct | CilLocation loc -> CilType.Location.hash loc let to_cil = function - | Node node -> UpdateCil0.getLoc node + | Node node -> UpdateCil0.getLoc node (* use incrementally updated location *) | CilLocation loc -> loc let to_yojson x = CilType.Location.to_yojson (to_cil x) From f9e3f4163402b3c6b30b407cf6b1c4fc52e6b37b Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Fri, 14 Jan 2022 15:18:24 +0200 Subject: [PATCH 176/402] Replace List.equal with BatList.eq for pre-OCaml 4.12 compatibility --- src/cdomains/lvalMapDomain.ml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cdomains/lvalMapDomain.ml b/src/cdomains/lvalMapDomain.ml index 4ed0d9b703..62f8245c2c 100644 --- a/src/cdomains/lvalMapDomain.ml +++ b/src/cdomains/lvalMapDomain.ml @@ -73,7 +73,7 @@ struct include Printable.Blank type t = { key: k; loc: Node.t list; state: s } let hash = Hashtbl.hash - let equal a b = Lval.CilLval.equal a.key b.key && List.equal Node.equal a.loc b.loc && a.state = b.state + let equal a b = Lval.CilLval.equal a.key b.key && BatList.eq Node.equal a.loc b.loc && a.state = b.state let compare a b = let r = Lval.CilLval.compare a.key b.key in From b9dcafbab76b44d39aa1e1287fa65f8652957772 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Fri, 14 Jan 2022 15:24:08 +0200 Subject: [PATCH 177/402] Remove fixed TODO in 01-cpa/55-dead-branch-multiple --- tests/regression/01-cpa/55-dead-branch-multiple.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/regression/01-cpa/55-dead-branch-multiple.c b/tests/regression/01-cpa/55-dead-branch-multiple.c index 8a0c7a9bd7..4df507837c 100644 --- a/tests/regression/01-cpa/55-dead-branch-multiple.c +++ b/tests/regression/01-cpa/55-dead-branch-multiple.c @@ -4,7 +4,7 @@ int main() { int a = 1; int b = 0; - if (a && b) { // TODO WARN + if (a && b) { // WARN assert(0); // NOWARN (unreachable) } From e8206754cb46fb8468429f0e448c49592aabc381 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Fri, 14 Jan 2022 15:47:54 +0200 Subject: [PATCH 178/402] Update Gobview for message nodes --- gobview | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gobview b/gobview index 3acd89c9ec..97244ba9c1 160000 --- a/gobview +++ b/gobview @@ -1 +1 @@ -Subproject commit 3acd89c9ec9b0714433ae3b9aa82d596a5c34aac +Subproject commit 97244ba9c1835e2928ece72d9e33bef339a2f491 From 4b4bfd4adbea141f9d28f44ea28c3b2bd2682a91 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Sun, 16 Jan 2022 18:03:54 +0200 Subject: [PATCH 179/402] Update gobview rebased for OCaml 4.13 --- gobview | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gobview b/gobview index 97244ba9c1..3dca6427a0 160000 --- a/gobview +++ b/gobview @@ -1 +1 @@ -Subproject commit 97244ba9c1835e2928ece72d9e33bef339a2f491 +Subproject commit 3dca6427a00d8732dd7a2d78af4566701fcca345 From 5551b71e0b4ed6f6c526ae091dd1a01ee8cb88c4 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 19 Jan 2022 13:52:54 +0200 Subject: [PATCH 180/402] Add basic framework for querying constraint variables --- src/analyses/mCP.ml | 6 ++++++ src/analyses/mutexAnalysis.ml | 2 ++ src/domains/queries.ml | 5 +++++ src/framework/analyses.ml | 3 +++ src/framework/constraints.ml | 25 +++++++++++++++++++++++++ src/framework/varQuery.ml | 4 ++++ src/solvers/td3.ml | 12 ++++++++++++ 7 files changed, 57 insertions(+) create mode 100644 src/framework/varQuery.ml diff --git a/src/analyses/mCP.ml b/src/analyses/mCP.ml index 78cfada64b..d0dd1797d7 100644 --- a/src/analyses/mCP.ml +++ b/src/analyses/mCP.ml @@ -688,6 +688,12 @@ struct (* WarnGlobal is special: it only goes to corresponding analysis and the argument variant is unlifted for it *) let (n, g): V.t = Obj.obj g in f ~q:(WarnGlobal (Obj.repr g)) (Result.top ()) (n, spec n, assoc n ctx.local) + | Queries.IterSysVars (vq, fi) -> + iter (fun ((n,(module S:MCPSpec),d) as t) -> + let fi' x = fi (Obj.repr (v_of n x)) in + let q' = Queries.IterSysVars (vq, fi') in + f ~q:q' () t + ) @@ spec_list ctx.local (* | EvalInt e -> (* TODO: only query others that actually respond to EvalInt *) (* 2x speed difference on SV-COMP nla-digbench-scaling/ps6-ll_valuebound5.c *) diff --git a/src/analyses/mutexAnalysis.ml b/src/analyses/mutexAnalysis.ml index 7bb523d958..22d4050073 100644 --- a/src/analyses/mutexAnalysis.ml +++ b/src/analyses/mutexAnalysis.ml @@ -171,6 +171,8 @@ struct Mutexes.mem verifier_atomic held_locks | Queries.PartAccess {exp; var_opt; write} -> part_access ctx exp var_opt write + | Queries.IterSysVars (Global g, f) -> + f (Obj.repr g) | _ -> Queries.Result.top q diff --git a/src/domains/queries.ml b/src/domains/queries.ml index a72f3fdc65..6ec749a40e 100644 --- a/src/domains/queries.ml +++ b/src/domains/queries.ml @@ -97,6 +97,7 @@ type _ t = | CreatedThreads: ConcDomain.ThreadSet.t t | MustJoinedThreads: ConcDomain.MustThreadSet.t t | WarnGlobal: Obj.t -> Unit.t t (** Argument must be of corresponding [Spec.V.t]. *) + | IterSysVars: VarQuery.t * (Obj.t -> unit) -> Unit.t t type 'a result = 'a @@ -149,6 +150,7 @@ struct | CreatedThreads -> (module ConcDomain.ThreadSet) | MustJoinedThreads -> (module ConcDomain.MustThreadSet) | WarnGlobal _ -> (module Unit) + | IterSysVars _ -> (module Unit) (** Get bottom result for query. *) let bot (type a) (q: a t): a result = @@ -200,6 +202,7 @@ struct | CreatedThreads -> ConcDomain.ThreadSet.top () | MustJoinedThreads -> ConcDomain.MustThreadSet.top () | WarnGlobal _ -> Unit.top () + | IterSysVars _ -> Unit.top () end (* The type any_query can't be directly defined in Any as t, @@ -249,6 +252,7 @@ struct | Any CreatedThreads -> 33 | Any MustJoinedThreads -> 34 | Any (WarnGlobal _) -> 35 + | Any (IterSysVars _) -> 36 in let r = Stdlib.compare (order a) (order b) in if r <> 0 then @@ -284,6 +288,7 @@ struct | Any (IsMultiple v1), Any (IsMultiple v2) -> CilType.Varinfo.compare v1 v2 | Any (EvalThread e1), Any (EvalThread e2) -> CilType.Exp.compare e1 e2 | Any (WarnGlobal vi1), Any (WarnGlobal vi2) -> compare (Hashtbl.hash vi1) (Hashtbl.hash vi2) + | Any (IterSysVars (vq1, f1)), Any (IterSysVars (vq2, f2)) -> VarQuery.compare vq1 vq2 (* not comparing fs *) (* only argumentless queries should remain *) | _, _ -> Stdlib.compare (order a) (order b) end diff --git a/src/framework/analyses.ml b/src/framework/analyses.ml index cdc8f3e42d..c717f79956 100644 --- a/src/framework/analyses.ml +++ b/src/framework/analyses.ml @@ -420,6 +420,8 @@ sig (** Data used for incremental analysis *) val increment : increment_data + + val iter_vars: (v -> d) -> VarQuery.t -> (v -> unit) -> unit end (** Any system of side-effecting equations over lattices. *) @@ -435,6 +437,7 @@ sig module G : Lattice.S val increment : increment_data val system : LVar.t -> ((LVar.t -> D.t) -> (LVar.t -> D.t -> unit) -> (GVar.t -> G.t) -> (GVar.t -> G.t -> unit) -> D.t) option + val iter_vars: (LVar.t -> D.t) -> (GVar.t -> G.t) -> VarQuery.t -> (LVar.t -> unit) -> (GVar.t -> unit) -> unit end (** A solver is something that can translate a system into a solution (hash-table). diff --git a/src/framework/constraints.ml b/src/framework/constraints.ml index bb9e24adc8..a76ec18591 100644 --- a/src/framework/constraints.ml +++ b/src/framework/constraints.ml @@ -745,6 +745,28 @@ struct List.fold_left S.D.join (S.D.bot ()) xs in Some tf + + let iter_vars getl getg vq fl fg = + let rec ctx = + { ask = (fun (type a) (q: a Queries.t) -> S.query ctx q) + ; emit = (fun _ -> failwith "Cannot \"emit\" in query context.") + ; node = MyCFG.dummy_node (* TODO maybe ask should take a node (which could be used here) instead of a location *) + ; prev_node = MyCFG.dummy_node + ; control_context = Obj.repr (fun () -> ctx_failwith "No context in query context.") + ; context = (fun () -> ctx_failwith "No context in query context.") + ; edge = MyCFG.Skip + ; local = S.startstate Cil.dummyFunDec.svar + ; global = getg + ; presub = [] + ; postsub= [] + ; spawn = (fun v d -> failwith "Cannot \"spawn\" in query context.") + ; split = (fun d es -> failwith "Cannot \"split\" in query context.") + ; sideg = (fun v g -> failwith "Cannot \"split\" in query context.") + ; assign = (fun ?name _ -> failwith "Cannot \"assign\" in query context.") + } + in + let f v = fg (Obj.obj v) in + S.query ctx (IterSysVars (vq, f)) end (** Convert a non-incremental solver into an "incremental" solver. @@ -842,6 +864,9 @@ struct let system = function | `G _ -> None | `L x -> Option.map conv (S.system x) + + let iter_vars get vq f = + S.iter_vars (getL % get % l) (getG % get % g) vq (f % l) (f % g) end (** Splits a [EqConstrSys] solution into a [GlobConstrSys] solution with given [Hashtbl.S] for the [EqConstrSys]. *) diff --git a/src/framework/varQuery.ml b/src/framework/varQuery.ml new file mode 100644 index 0000000000..270e761dc2 --- /dev/null +++ b/src/framework/varQuery.ml @@ -0,0 +1,4 @@ +type t = + | Global of CilType.Varinfo.t + (* TODO: add Node, Function *) +[@@deriving ord] diff --git a/src/solvers/td3.ml b/src/solvers/td3.ml index 4cff35dfc5..23a5aaad25 100644 --- a/src/solvers/td3.ml +++ b/src/solvers/td3.ml @@ -905,6 +905,18 @@ module WP = print_data data "Data after postsolve"; + Cil.iterGlobals !Cilfacade.current_file (function + | GVar (g, _, _) -> + ignore (Pretty.printf "%a:\n" CilType.Varinfo.pretty g); + let get x = try HM.find rho x with Not_found -> S.Dom.bot () in + S.iter_vars get (Global g) (fun v -> + let d = get v in + if not (S.Dom.is_bot d) then + ignore (Pretty.printf " %a: %a\n" S.Var.pretty_trace v S.Dom.pretty d) + ) + | _ -> () + ); + {st; infl; sides; rho; wpoint; stable; side_dep; side_infl; var_messages} let solve box st vs = From d1200fc9d511a5ef7e7098bcf967e70c30617622 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 19 Jan 2022 14:05:07 +0200 Subject: [PATCH 181/402] Implement IterSysVars for base --- src/analyses/base.ml | 3 +++ src/analyses/basePriv.ml | 20 ++++++++++++++++++++ src/analyses/basePriv.mli | 1 + src/analyses/commonPriv.ml | 4 ++++ src/framework/varQuery.ml | 2 ++ 5 files changed, 30 insertions(+) diff --git a/src/analyses/base.ml b/src/analyses/base.ml index c962bb9907..a0df23d62a 100644 --- a/src/analyses/base.ml +++ b/src/analyses/base.ml @@ -1082,6 +1082,9 @@ struct | _ -> true end | Q.IsMultiple v -> WeakUpdates.mem v ctx.local.weak + | Q.IterSysVars (vq, vf) -> + let vf' x = vf (Obj.repr (V.priv x)) in + Priv.iter_sys_vars (priv_getg ctx.global) vq vf' | _ -> Q.Result.top q let update_variable variable typ value cpa = diff --git a/src/analyses/basePriv.ml b/src/analyses/basePriv.ml index 7d8d7179f2..109279f2c3 100644 --- a/src/analyses/basePriv.ml +++ b/src/analyses/basePriv.ml @@ -35,6 +35,7 @@ sig val escape: Q.ask -> (V.t -> G.t) -> (V.t -> G.t -> unit) -> BaseComponents (D).t -> EscapeDomain.EscapedVars.t -> BaseComponents (D).t val enter_multithreaded: Q.ask -> (V.t -> G.t) -> (V.t -> G.t -> unit) -> BaseComponents (D).t -> BaseComponents (D).t val threadenter: Q.ask -> BaseComponents (D).t -> BaseComponents (D).t + val iter_sys_vars: (V.t -> G.t) -> VarQuery.t -> V.t VarQuery.f -> unit val init: unit -> unit val finalize: unit -> unit @@ -124,6 +125,10 @@ struct in (* We fold over the local state, and side effect the globals *) CPA.fold side_var st.cpa st + + let iter_sys_vars getg vq vf = + match vq with + | VarQuery.Global g -> vf g end (** Protection-Based Reading old implementation. @@ -184,6 +189,10 @@ struct in (* We fold over the local state, and side effect the globals *) CPA.fold side_var st.cpa st + + let iter_sys_vars getg vq vf = + match vq with + | VarQuery.Global g -> vf g end module PerMutexPrivBase = @@ -473,6 +482,10 @@ struct CPA.fold side_var st.cpa st let threadenter = old_threadenter + + let iter_sys_vars getg vq vf = + match vq with + | VarQuery.Global g -> vf g end module type PerGlobalPrivParam = @@ -599,6 +612,12 @@ struct ) st.cpa st let threadenter = startstate_threadenter startstate + + let iter_sys_vars getg vq vf = + match vq with + | VarQuery.Global g -> + vf (V.unprotected g); + vf (V.protected g); end module AbstractLockCenteredGBase (WeakRange: Lattice.S) (SyncRange: Lattice.S) = @@ -1351,6 +1370,7 @@ struct let escape ask getg sideg st escaped = time "escape" (Priv.escape ask getg sideg st) escaped let enter_multithreaded ask getg sideg st = time "enter_multithreaded" (Priv.enter_multithreaded ask getg sideg) st let threadenter ask st = time "threadenter" (Priv.threadenter ask) st + let iter_sys_vars getg vq vf = time "iter_sys_vars" (Priv.iter_sys_vars getg vq) vf let init () = time "init" (Priv.init) () let finalize () = time "finalize" (Priv.finalize) () diff --git a/src/analyses/basePriv.mli b/src/analyses/basePriv.mli index 67effa55bf..1dc413ebfc 100644 --- a/src/analyses/basePriv.mli +++ b/src/analyses/basePriv.mli @@ -21,6 +21,7 @@ sig val escape: Queries.ask -> (V.t -> G.t) -> (V.t -> G.t -> unit) -> BaseDomain.BaseComponents (D).t -> EscapeDomain.EscapedVars.t -> BaseDomain.BaseComponents (D).t val enter_multithreaded: Queries.ask -> (V.t -> G.t) -> (V.t -> G.t -> unit) -> BaseDomain.BaseComponents (D).t -> BaseDomain.BaseComponents (D).t val threadenter: Queries.ask -> BaseDomain.BaseComponents (D).t -> BaseDomain.BaseComponents (D).t + val iter_sys_vars: (V.t -> G.t) -> VarQuery.t -> V.t VarQuery.f -> unit val init: unit -> unit val finalize: unit -> unit diff --git a/src/analyses/commonPriv.ml b/src/analyses/commonPriv.ml index 98e140f86c..829eaefbab 100644 --- a/src/analyses/commonPriv.ml +++ b/src/analyses/commonPriv.ml @@ -89,6 +89,10 @@ struct let mutex_inits: t = `Left (`Right ()) let global x: t = `Right x end + + let iter_sys_vars getg vq vf = + match vq with + | VarQuery.Global g -> vf (V.global g) end module MayVars = diff --git a/src/framework/varQuery.ml b/src/framework/varQuery.ml index 270e761dc2..0254a9b54c 100644 --- a/src/framework/varQuery.ml +++ b/src/framework/varQuery.ml @@ -2,3 +2,5 @@ type t = | Global of CilType.Varinfo.t (* TODO: add Node, Function *) [@@deriving ord] + +type 'v f = 'v -> unit From 05e1c377de8db247f816db8f5f1b2f3897189344 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 19 Jan 2022 14:52:02 +0200 Subject: [PATCH 182/402] Implement IterSysVars for access --- src/analyses/accessAnalysis.ml | 77 +++++++++++++++++++++++++++------- 1 file changed, 61 insertions(+), 16 deletions(-) diff --git a/src/analyses/accessAnalysis.ml b/src/analyses/accessAnalysis.ml index e636d703f9..74e8b76070 100644 --- a/src/analyses/accessAnalysis.ml +++ b/src/analyses/accessAnalysis.ml @@ -17,13 +17,32 @@ struct module D = Lattice.Unit module C = Lattice.Unit + module V0 = Printable.Prod (Access.LVOpt) (Access.T) + module V = + struct + include Printable.Either (V0) (CilType.Varinfo) + let access x = `Left x + let vars x = `Right x + end + + module V0Set = SetDomain.Make (V0) module G = struct - include Access.PM + include Lattice.Lift2 (Access.PM) (V0Set) (Printable.DefaultNames) + + let access = function + | `Bot -> Access.PM.bot () + | `Lifted1 x -> x + | _ -> failwith "Access.access" + let vars = function + | `Bot -> V0Set.bot () + | `Lifted2 x -> x + | _ -> failwith "Access.vars" + let create_access access = `Lifted1 access + let create_vars vars = `Lifted2 vars let leq x y = !GU.postsolving || leq x y (* HACK: to pass verify*) end - module V = Printable.Prod (Access.LVOpt) (Access.T) let safe = ref 0 let vulnerable = ref 0 @@ -34,18 +53,35 @@ struct vulnerable := 0; unsafe := 0 - let side_access ctx ty lv_opt ls_opt (conf, w, loc, e, lp) = - if !GU.should_warn then ( + let side_vars ctx lv_opt ty = + match lv_opt with + | Some (v, _) -> let d = - let open Access in - PM.singleton ls_opt ( - AS.singleton (conf, w, loc, e, lp) - ) + if !GU.should_warn then + G.create_vars (V0Set.singleton (lv_opt, ty)) + else + G.bot () (* HACK: just to pass validation with MCP DomVariantLattice *) in - ctx.sideg (lv_opt, ty) d - ) - else - ctx.sideg (lv_opt, ty) (G.bot ()) (* HACK: just to pass validation with MCP DomVariantLattice *) + ctx.sideg (V.vars v) d; + | None -> + () + + let side_access ctx ty lv_opt ls_opt (conf, w, loc, e, lp) = + let d = + if !GU.should_warn then ( + let d = + let open Access in + PM.singleton ls_opt ( + AS.singleton (conf, w, loc, e, lp) + ) + in + G.create_access d + ) + else + G.bot () (* HACK: just to pass validation with MCP DomVariantLattice *) + in + ctx.sideg (V.access (lv_opt, ty)) d; + side_vars ctx lv_opt ty let do_access (ctx: (D.t, G.t, C.t, V.t) ctx) (w:bool) (reach:bool) (conf:int) (e:exp) = let open Queries in @@ -208,10 +244,19 @@ struct match q with | WarnGlobal g -> let g: V.t = Obj.obj g in - (* ignore (Pretty.printf "WarnGlobal %a\n" CilType.Varinfo.pretty g); *) - let pm = ctx.global g in - Access.print_accesses g pm; - Access.incr_summary safe vulnerable unsafe g pm + begin match g with + | `Left g -> + (* ignore (Pretty.printf "WarnGlobal %a\n" CilType.Varinfo.pretty g); *) + let pm = G.access (ctx.global (V.access g)) in + Access.print_accesses g pm; + Access.incr_summary safe vulnerable unsafe g pm + | `Right _ -> + () + end + | IterSysVars (Global g, vf) -> + V0Set.iter (fun (lv_opt, ty) -> + vf (Obj.repr (V.access (lv_opt, ty))) + ) (G.vars (ctx.global (V.vars g))) | _ -> Queries.Result.top q let finalize () = From 6d292811837ae1dbb4fe6c430532cddf96abd77f Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 19 Jan 2022 15:01:42 +0200 Subject: [PATCH 183/402] Implement IterSysVars for apron --- src/analyses/apron/apronAnalysis.apron.ml | 3 +++ src/analyses/apron/apronPriv.apron.ml | 8 ++++++++ 2 files changed, 11 insertions(+) diff --git a/src/analyses/apron/apronAnalysis.apron.ml b/src/analyses/apron/apronAnalysis.apron.ml index e8e1be7f6b..8d05557b47 100644 --- a/src/analyses/apron/apronAnalysis.apron.ml +++ b/src/analyses/apron/apronAnalysis.apron.ml @@ -377,6 +377,9 @@ struct let exp = (BinOp (Cil.Lt, exp1, exp2, TInt (IInt, []))) in let is_lt = eval_int exp in Option.default true (ID.to_bool is_lt) + | Queries.IterSysVars (vq, vf) -> + let vf' x = vf (Obj.repr x) in + Priv.iter_sys_vars ctx.global vq vf' | _ -> Result.top q diff --git a/src/analyses/apron/apronPriv.apron.ml b/src/analyses/apron/apronPriv.apron.ml index fa91f66f4b..cfc5a27347 100644 --- a/src/analyses/apron/apronPriv.apron.ml +++ b/src/analyses/apron/apronPriv.apron.ml @@ -39,6 +39,7 @@ module type S = val thread_join: Q.ask -> (V.t -> G.t) -> Cil.exp -> apron_components_t -> apron_components_t val thread_return: Q.ask -> (V.t -> G.t) -> (V.t -> G.t -> unit) -> ThreadIdDomain.Thread.t -> apron_components_t -> apron_components_t + val iter_sys_vars: (V.t -> G.t) -> VarQuery.t -> V.t VarQuery.f -> unit val init: unit -> unit val finalize: unit -> unit @@ -68,6 +69,7 @@ struct let enter_multithreaded ask getg sideg st = st let threadenter ask getg st = st + let iter_sys_vars getg vq vf = () let init () = () let finalize () = () @@ -342,6 +344,8 @@ struct let threadenter ask getg (st: apron_components_t): apron_components_t = {apr = getg (); priv = startstate ()} + let iter_sys_vars getg vq vf = () (* TODO: or report singleton global for any Global query? *) + let finalize () = () end @@ -1050,6 +1054,10 @@ struct let _,lmust,l = st.priv in {apr = AD.bot (); priv = (W.bot (),lmust,l)} + let iter_sys_vars getg vq vf = + match vq with + | VarQuery.Global g -> vf (V.global g) + let finalize () = finalize () end From 97b9b3bfbfb7b47d30f303e01ba13a1d090820c6 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 19 Jan 2022 15:03:41 +0200 Subject: [PATCH 184/402] Fix solver unit test compilation --- unittest/solver/solverTest.ml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/unittest/solver/solverTest.ml b/unittest/solver/solverTest.ml index d77dd4688c..8a4b1bf87e 100644 --- a/unittest/solver/solverTest.ml +++ b/unittest/solver/solverTest.ml @@ -43,6 +43,8 @@ module ConstrSys = struct | "z" -> Some (fun loc _ glob gside -> (ignore (loc "y"); loc "y")) | "w" -> Some (fun loc _ glob gside -> (gside "g" (Int.of_int (Z.of_int64 42L)); ignore (loc "z"); try Int.add (loc "w") (Int.of_int (Z.of_int64 1L)) with IntDomain.ArithmeticOnIntegerBot _ -> Int.top ())) | _ -> None + + let iter_vars _ _ _ _ _ = () end module LH = BatHashtbl.Make (ConstrSys.LVar) From fb067147fadd8a5abefe091580ba4ee99ef70e92 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 19 Jan 2022 15:41:22 +0200 Subject: [PATCH 185/402] Change FromSpec globals to either --- src/framework/analyses.ml | 5 ++++- src/framework/constraints.ml | 8 ++++---- src/framework/control.ml | 17 +++++++++++------ src/witness/witness.ml | 2 +- 4 files changed, 20 insertions(+), 12 deletions(-) diff --git a/src/framework/analyses.ml b/src/framework/analyses.ml index c717f79956..66f5bada41 100644 --- a/src/framework/analyses.ml +++ b/src/framework/analyses.ml @@ -70,7 +70,10 @@ end module GVarF (V: Printable.S) = struct - include V + include Printable.Either (V) (CilType.Fundec) + let spec x = `Left x + let contexts x = `Right x + (* from Basetype.Variables *) let var_id _ = "globals" let node _ = MyCFG.Function Cil.dummyFunDec diff --git a/src/framework/constraints.ml b/src/framework/constraints.ml index a76ec18591..d707227936 100644 --- a/src/framework/constraints.ml +++ b/src/framework/constraints.ml @@ -493,12 +493,12 @@ struct ; context = snd var |> Obj.obj ; edge = edge ; local = pval - ; global = getg + ; global = (fun g -> getg (GVar.spec g)) ; presub = [] ; postsub = [] ; spawn = spawn ; split = (fun (d:D.t) es -> assert (List.is_empty es); r := d::!r) - ; sideg = sideg + ; sideg = (fun g d -> sideg (GVar.spec g) d) ; assign = (fun ?name _ -> failwith "Cannot \"assign\" in common context.") } and spawn lval f args = @@ -756,7 +756,7 @@ struct ; context = (fun () -> ctx_failwith "No context in query context.") ; edge = MyCFG.Skip ; local = S.startstate Cil.dummyFunDec.svar - ; global = getg + ; global = (fun g -> getg (GVar.spec g)) ; presub = [] ; postsub= [] ; spawn = (fun v d -> failwith "Cannot \"spawn\" in query context.") @@ -765,7 +765,7 @@ struct ; assign = (fun ?name _ -> failwith "Cannot \"assign\" in query context.") } in - let f v = fg (Obj.obj v) in + let f v = fg (GVar.spec (Obj.obj v)) in S.query ctx (IterSysVars (vq, f)) end diff --git a/src/framework/control.ml b/src/framework/control.ml index 38e3f13547..72982edbb6 100644 --- a/src/framework/control.ml +++ b/src/framework/control.ml @@ -198,7 +198,7 @@ struct let make_global_fast_xml f g = let open Printf in let print_globals k v = - fprintf f "\n%s%a" (XmlUtil.escape (Spec.V.show k)) Spec.G.printXml v; + fprintf f "\n%s%a" (XmlUtil.escape (EQSys.GVar.show k)) Spec.G.printXml v; in GHT.iter print_globals g in @@ -224,10 +224,11 @@ struct (* Simulate globals before analysis. *) (* TODO: make extern/global inits part of constraint system so all of this would be unnecessary. *) let gh = GHT.create 13 in - let getg v = GHT.find_default gh v (Spec.G.bot ()) in + let getg v = GHT.find_default gh (EQSys.GVar.spec v) (Spec.G.bot ()) in let sideg v d = + let v' = EQSys.GVar.spec v in if M.tracing then M.trace "global_inits" "sideg %a = %a\n" Spec.V.pretty v Spec.G.pretty d; - GHT.replace gh v (Spec.G.join (getg v) d) + GHT.replace gh v' (Spec.G.join (getg v) d) in (* Old-style global function for context. * This indirectly prevents global initializers from depending on each others' global side effects, which would require proper solving. *) @@ -568,7 +569,7 @@ struct ; context = (fun () -> ctx_failwith "No context in query context.") ; edge = MyCFG.Skip ; local = Hashtbl.find joined loc - ; global = GHT.find gh + ; global = (fun g -> GHT.find gh (EQSys.GVar.spec g)) ; presub = [] ; postsub= [] ; spawn = (fun v d -> failwith "Cannot \"spawn\" in query context.") @@ -623,7 +624,7 @@ struct ; context = (fun () -> ctx_failwith "No context in query context.") ; edge = MyCFG.Skip ; local = snd (List.hd startvars) (* bot and top both silently raise and catch Deadcode in DeadcodeLifter *) - ; global = (fun v -> try GHT.find gh v with Not_found -> EQSys.G.bot ()) + ; global = (fun v -> try GHT.find gh (EQSys.GVar.spec v) with Not_found -> EQSys.G.bot ()) ; presub = [] ; postsub= [] ; spawn = (fun v d -> failwith "Cannot \"spawn\" in query context.") @@ -632,7 +633,11 @@ struct ; assign = (fun ?name _ -> failwith "Cannot \"assign\" in query context.") } in - Spec.query ctx (WarnGlobal (Obj.repr g)) + match g with + | `Left g -> + Spec.query ctx (WarnGlobal (Obj.repr g)) + | `Right _ -> + () in Stats.time "warn_global" (GHT.iter warn_global) gh; diff --git a/src/witness/witness.ml b/src/witness/witness.ml index 155902f29b..c1f6686b70 100644 --- a/src/witness/witness.ml +++ b/src/witness/witness.ml @@ -303,7 +303,7 @@ struct ; context = (fun () -> snd lvar) ; edge = MyCFG.Skip ; local = local - ; global = GHT.find gh + ; global = (fun g -> GHT.find gh (EQSys.GVar.spec g)) ; presub = [] ; postsub= [] ; spawn = (fun v d -> failwith "Cannot \"spawn\" in witness context.") From c75f8f737484113a32b9177a04ab033cfe42210d Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 19 Jan 2022 15:57:04 +0200 Subject: [PATCH 186/402] Change FromSpec global domain to either --- src/framework/analyses.ml | 17 +++++++++++++++++ src/framework/constraints.ml | 15 ++++++++------- src/framework/control.ml | 12 ++++++------ src/witness/witness.ml | 4 ++-- 4 files changed, 33 insertions(+), 15 deletions(-) diff --git a/src/framework/analyses.ml b/src/framework/analyses.ml index 66f5bada41..19a7c24174 100644 --- a/src/framework/analyses.ml +++ b/src/framework/analyses.ml @@ -80,6 +80,23 @@ struct let pretty_trace = pretty end +module GVarG (G: Lattice.S) (C: Printable.S) = +struct + module CSet = SetDomain.Make (C) + include Lattice.Lift2 (G) (CSet) (Printable.DefaultNames) + + let spec = function + | `Bot -> G.bot () + | `Lifted1 x -> x + | _ -> failwith "GVarG.spec" + let contexts = function + | `Bot -> CSet.bot () + | `Lifted2 x -> x + | _ -> failwith "GVarG.contexts" + let create_spec spec = `Lifted1 spec + let create_contexts contexts = `Lifted2 contexts +end + exception Deadcode diff --git a/src/framework/constraints.ml b/src/framework/constraints.ml index d707227936..3ecac6d7ce 100644 --- a/src/framework/constraints.ml +++ b/src/framework/constraints.ml @@ -458,7 +458,7 @@ module FromSpec (S:Spec) (Cfg:CfgBackward) (I: Increment) include GlobConstrSys with module LVar = VarF (S.C) and module GVar = GVarF (S.V) and module D = S.D - and module G = S.G + and module G = GVarG (S.G) (S.C) val tf : MyCFG.node * S.C.t -> (Cil.location * MyCFG.edge) list * MyCFG.node -> D.t -> ((MyCFG.node * S.C.t) -> S.D.t) -> (MyCFG.node * S.C.t -> S.D.t -> unit) -> (GVar.t -> G.t) -> (GVar.t -> G.t -> unit) -> D.t end = @@ -470,7 +470,7 @@ struct module LVar = VarF (S.C) module GVar = GVarF (S.V) module D = S.D - module G = S.G + module G = GVarG (S.G) (S.C) (* Dummy module. No incremental analysis supported here*) let increment = I.increment @@ -480,7 +480,7 @@ struct | _ :: _ :: _ -> S.sync ctx `Join | _ -> S.sync ctx `Normal - let common_ctx var edge prev_node pval (getl:lv -> ld) sidel getg sideg : (D.t, G.t, S.C.t, S.V.t) ctx * D.t list ref * (lval option * varinfo * exp list * D.t) list ref = + let common_ctx var edge prev_node pval (getl:lv -> ld) sidel getg sideg : (D.t, S.G.t, S.C.t, S.V.t) ctx * D.t list ref * (lval option * varinfo * exp list * D.t) list ref = let r = ref [] in let spawns = ref [] in (* now watch this ... *) @@ -493,12 +493,12 @@ struct ; context = snd var |> Obj.obj ; edge = edge ; local = pval - ; global = (fun g -> getg (GVar.spec g)) + ; global = (fun g -> G.spec (getg (GVar.spec g))) ; presub = [] ; postsub = [] ; spawn = spawn ; split = (fun (d:D.t) es -> assert (List.is_empty es); r := d::!r) - ; sideg = (fun g d -> sideg (GVar.spec g) d) + ; sideg = (fun g d -> sideg (GVar.spec g) (G.create_spec d)) ; assign = (fun ?name _ -> failwith "Cannot \"assign\" in common context.") } and spawn lval f args = @@ -756,7 +756,7 @@ struct ; context = (fun () -> ctx_failwith "No context in query context.") ; edge = MyCFG.Skip ; local = S.startstate Cil.dummyFunDec.svar - ; global = (fun g -> getg (GVar.spec g)) + ; global = (fun g -> G.spec (getg (GVar.spec g))) ; presub = [] ; postsub= [] ; spawn = (fun v d -> failwith "Cannot \"spawn\" in query context.") @@ -1109,12 +1109,13 @@ module Compare (Sys:GlobConstrSys with module LVar = VarF (S.C) and module GVar = GVarF (S.V) and module D = S.D - and module G = S.G) + and module G = GVarG (S.G) (S.C)) (LH:Hashtbl.S with type key=Sys.LVar.t) (GH:Hashtbl.S with type key=Sys.GVar.t) = struct open S + module G = Sys.G module PP = Hashtbl.Make (Node) diff --git a/src/framework/control.ml b/src/framework/control.ml index 72982edbb6..30690e5866 100644 --- a/src/framework/control.ml +++ b/src/framework/control.ml @@ -198,7 +198,7 @@ struct let make_global_fast_xml f g = let open Printf in let print_globals k v = - fprintf f "\n%s%a" (XmlUtil.escape (EQSys.GVar.show k)) Spec.G.printXml v; + fprintf f "\n%s%a" (XmlUtil.escape (EQSys.GVar.show k)) EQSys.G.printXml v; in GHT.iter print_globals g in @@ -224,11 +224,11 @@ struct (* Simulate globals before analysis. *) (* TODO: make extern/global inits part of constraint system so all of this would be unnecessary. *) let gh = GHT.create 13 in - let getg v = GHT.find_default gh (EQSys.GVar.spec v) (Spec.G.bot ()) in + let getg v = GHT.find_default gh (EQSys.GVar.spec v) (EQSys.G.create_spec (Spec.G.bot ())) in let sideg v d = let v' = EQSys.GVar.spec v in if M.tracing then M.trace "global_inits" "sideg %a = %a\n" Spec.V.pretty v Spec.G.pretty d; - GHT.replace gh v' (Spec.G.join (getg v) d) + GHT.replace gh v' (EQSys.G.create_spec (Spec.G.join (EQSys.G.spec (getg v)) d)) in (* Old-style global function for context. * This indirectly prevents global initializers from depending on each others' global side effects, which would require proper solving. *) @@ -288,7 +288,7 @@ struct let print_globals glob = let out = M.get_out (Spec.name ()) !GU.out in let print_one v st = - ignore (Pretty.fprintf out "%a -> %a\n" EQSys.GVar.pretty_trace v Spec.G.pretty st) + ignore (Pretty.fprintf out "%a -> %a\n" EQSys.GVar.pretty_trace v EQSys.G.pretty st) in GHT.iter print_one glob in @@ -569,7 +569,7 @@ struct ; context = (fun () -> ctx_failwith "No context in query context.") ; edge = MyCFG.Skip ; local = Hashtbl.find joined loc - ; global = (fun g -> GHT.find gh (EQSys.GVar.spec g)) + ; global = (fun g -> EQSys.G.spec (GHT.find gh (EQSys.GVar.spec g))) ; presub = [] ; postsub= [] ; spawn = (fun v d -> failwith "Cannot \"spawn\" in query context.") @@ -624,7 +624,7 @@ struct ; context = (fun () -> ctx_failwith "No context in query context.") ; edge = MyCFG.Skip ; local = snd (List.hd startvars) (* bot and top both silently raise and catch Deadcode in DeadcodeLifter *) - ; global = (fun v -> try GHT.find gh (EQSys.GVar.spec v) with Not_found -> EQSys.G.bot ()) + ; global = (fun v -> EQSys.G.spec (try GHT.find gh (EQSys.GVar.spec v) with Not_found -> EQSys.G.bot ())) ; presub = [] ; postsub= [] ; spawn = (fun v d -> failwith "Cannot \"spawn\" in query context.") diff --git a/src/witness/witness.ml b/src/witness/witness.ml index c1f6686b70..909b67f87f 100644 --- a/src/witness/witness.ml +++ b/src/witness/witness.ml @@ -271,7 +271,7 @@ module Result (Cfg : CfgBidir) (EQSys : GlobConstrSys with module LVar = VarF (Spec.C) and module GVar = GVarF (Spec.V) and module D = Spec.D - and module G = Spec.G) + and module G = GVarG (Spec.G) (Spec.C)) (LHT : BatHashtbl.S with type key = EQSys.LVar.t) (GHT : BatHashtbl.S with type key = EQSys.GVar.t) = struct @@ -303,7 +303,7 @@ struct ; context = (fun () -> snd lvar) ; edge = MyCFG.Skip ; local = local - ; global = (fun g -> GHT.find gh (EQSys.GVar.spec g)) + ; global = (fun g -> EQSys.G.spec (GHT.find gh (EQSys.GVar.spec g))) ; presub = [] ; postsub= [] ; spawn = (fun v d -> failwith "Cannot \"spawn\" in witness context.") From e55619e7e5339c3bd801b8121c217103e44a9aa7 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 19 Jan 2022 16:09:41 +0200 Subject: [PATCH 187/402] Add function context collecting --- src/framework/analyses.ml | 7 ++++++- src/framework/constraints.ml | 12 +++++++++++- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/src/framework/analyses.ml b/src/framework/analyses.ml index 19a7c24174..6f634e3b66 100644 --- a/src/framework/analyses.ml +++ b/src/framework/analyses.ml @@ -82,7 +82,12 @@ end module GVarG (G: Lattice.S) (C: Printable.S) = struct - module CSet = SetDomain.Make (C) + module CSet = + struct + include SetDomain.Make (C) + let leq x y = !GU.postsolving || leq x y (* HACK: to pass verify*) + end + include Lattice.Lift2 (G) (CSet) (Printable.DefaultNames) let spec = function diff --git a/src/framework/constraints.ml b/src/framework/constraints.ml index 3ecac6d7ce..6b79208859 100644 --- a/src/framework/constraints.ml +++ b/src/framework/constraints.ml @@ -480,6 +480,15 @@ struct | _ :: _ :: _ -> S.sync ctx `Join | _ -> S.sync ctx `Normal + let side_context sideg f c = + let d = + if !GU.postsolving then + G.create_contexts (G.CSet.singleton c) + else + G.create_contexts (G.CSet.empty ()) (* HACK: just to pass validation with MCP DomVariantLattice *) + in + sideg (GVar.contexts f) d + let common_ctx var edge prev_node pval (getl:lv -> ld) sidel getg sideg : (D.t, S.G.t, S.C.t, S.V.t) ctx * D.t list ref * (lval option * varinfo * exp list * D.t) list ref = let r = ref [] in let spawns = ref [] in @@ -511,6 +520,7 @@ struct | fd -> let c = S.context fd d in sidel (FunctionEntry fd, c) d; + side_context sideg fd c; ignore (getl (Function fd, c)) | exception Not_found -> (* unknown function *) @@ -620,7 +630,7 @@ struct in let paths = S.enter ctx lv f args in let paths = List.map (fun (c,v) -> (c, S.context f v, v)) paths in - List.iter (fun (c,fc,v) -> if not (S.D.is_bot v) then sidel (FunctionEntry f, fc) v) paths; + List.iter (fun (c,fc,v) -> if not (S.D.is_bot v) then (sidel (FunctionEntry f, fc) v; side_context sideg f fc)) paths; let paths = List.map (fun (c,fc,v) -> (c, fc, if S.D.is_bot v then v else getl (Function f, fc))) paths in let paths = List.filter (fun (c,fc,v) -> not (D.is_bot v)) paths in if M.tracing then M.traceli "combine" "combining\n"; From 803c16ce051c1c02a4f0ce67bef1e5a4291a0251 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 19 Jan 2022 16:18:08 +0200 Subject: [PATCH 188/402] Add VarQuery.Node --- src/analyses/apron/apronPriv.apron.ml | 1 + src/analyses/basePriv.ml | 4 ++++ src/analyses/commonPriv.ml | 1 + src/framework/constraints.ml | 12 +++++++++++- src/framework/varQuery.ml | 3 ++- src/solvers/td3.ml | 8 ++++++++ 6 files changed, 27 insertions(+), 2 deletions(-) diff --git a/src/analyses/apron/apronPriv.apron.ml b/src/analyses/apron/apronPriv.apron.ml index cfc5a27347..20ec478ea3 100644 --- a/src/analyses/apron/apronPriv.apron.ml +++ b/src/analyses/apron/apronPriv.apron.ml @@ -1057,6 +1057,7 @@ struct let iter_sys_vars getg vq vf = match vq with | VarQuery.Global g -> vf (V.global g) + | _ -> () let finalize () = finalize () end diff --git a/src/analyses/basePriv.ml b/src/analyses/basePriv.ml index 109279f2c3..10f4a2c0e7 100644 --- a/src/analyses/basePriv.ml +++ b/src/analyses/basePriv.ml @@ -129,6 +129,7 @@ struct let iter_sys_vars getg vq vf = match vq with | VarQuery.Global g -> vf g + | _ -> () end (** Protection-Based Reading old implementation. @@ -193,6 +194,7 @@ struct let iter_sys_vars getg vq vf = match vq with | VarQuery.Global g -> vf g + | _ -> () end module PerMutexPrivBase = @@ -486,6 +488,7 @@ struct let iter_sys_vars getg vq vf = match vq with | VarQuery.Global g -> vf g + | _ -> () end module type PerGlobalPrivParam = @@ -618,6 +621,7 @@ struct | VarQuery.Global g -> vf (V.unprotected g); vf (V.protected g); + | _ -> () end module AbstractLockCenteredGBase (WeakRange: Lattice.S) (SyncRange: Lattice.S) = diff --git a/src/analyses/commonPriv.ml b/src/analyses/commonPriv.ml index 829eaefbab..5ab10ff4b4 100644 --- a/src/analyses/commonPriv.ml +++ b/src/analyses/commonPriv.ml @@ -93,6 +93,7 @@ struct let iter_sys_vars getg vq vf = match vq with | VarQuery.Global g -> vf (V.global g) + | _ -> () end module MayVars = diff --git a/src/framework/constraints.ml b/src/framework/constraints.ml index 6b79208859..9701553d6f 100644 --- a/src/framework/constraints.ml +++ b/src/framework/constraints.ml @@ -776,7 +776,17 @@ struct } in let f v = fg (GVar.spec (Obj.obj v)) in - S.query ctx (IterSysVars (vq, f)) + S.query ctx (IterSysVars (vq, f)); + + match vq with + | Node n -> + let fd = Node.find_fundec n in + let cs = G.contexts (getg (GVar.contexts fd)) in + G.CSet.iter (fun c -> + fl (n, c) + ) cs + | _ -> + () end (** Convert a non-incremental solver into an "incremental" solver. diff --git a/src/framework/varQuery.ml b/src/framework/varQuery.ml index 0254a9b54c..02cf9c34cf 100644 --- a/src/framework/varQuery.ml +++ b/src/framework/varQuery.ml @@ -1,6 +1,7 @@ type t = | Global of CilType.Varinfo.t - (* TODO: add Node, Function *) + | Node of Node.t + (* TODO: add Function *) [@@deriving ord] type 'v f = 'v -> unit diff --git a/src/solvers/td3.ml b/src/solvers/td3.ml index 23a5aaad25..0da0ca9075 100644 --- a/src/solvers/td3.ml +++ b/src/solvers/td3.ml @@ -914,6 +914,14 @@ module WP = if not (S.Dom.is_bot d) then ignore (Pretty.printf " %a: %a\n" S.Var.pretty_trace v S.Dom.pretty d) ) + | GFun (fd, _) -> + ignore (Pretty.printf "%a:\n" CilType.Fundec.pretty fd); + let get x = try HM.find rho x with Not_found -> S.Dom.bot () in + S.iter_vars get (Node (FunctionEntry fd)) (fun v -> + let d = get v in + if not (S.Dom.is_bot d) then + ignore (Pretty.printf " %a: %a\n" S.Var.pretty_trace v S.Dom.pretty d) + ) | _ -> () ); From 726ab6e3b5f0a34be5ff89a646d19def592e15c6 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 19 Jan 2022 16:32:21 +0200 Subject: [PATCH 189/402] Implement IterSysVars for dead-branch --- src/framework/constraints.ml | 9 ++++++++- src/solvers/td3.ml | 4 +++- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/src/framework/constraints.ml b/src/framework/constraints.ml index 3506e6c602..827ea9a006 100644 --- a/src/framework/constraints.ml +++ b/src/framework/constraints.ml @@ -1163,7 +1163,14 @@ struct end | IterSysVars (vq, vf) -> let vf' x = vf (Obj.repr (V.s (Obj.obj x))) in - S.query (conv ctx) (IterSysVars (vq, vf')) + S.query (conv ctx) (IterSysVars (vq, vf')); + + begin match vq with + | Node n -> + vf (Obj.repr (V.node n)) + | _ -> + () + end | _ -> S.query (conv ctx) q diff --git a/src/solvers/td3.ml b/src/solvers/td3.ml index 0da0ca9075..2ed6cb80b0 100644 --- a/src/solvers/td3.ml +++ b/src/solvers/td3.ml @@ -917,7 +917,9 @@ module WP = | GFun (fd, _) -> ignore (Pretty.printf "%a:\n" CilType.Fundec.pretty fd); let get x = try HM.find rho x with Not_found -> S.Dom.bot () in - S.iter_vars get (Node (FunctionEntry fd)) (fun v -> + (* let node: Node.t = FunctionEntry fd in *) + let node: Node.t = Statement (Cilfacade.getFirstStmt fd) in + S.iter_vars get (Node node) (fun v -> let d = get v in if not (S.Dom.is_bot d) then ignore (Pretty.printf " %a: %a\n" S.Var.pretty_trace v S.Dom.pretty d) From d6b8ec1e945f04d9f812662632335bd154a0c9a0 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 19 Jan 2022 16:37:08 +0200 Subject: [PATCH 190/402] Add more var query printing --- src/solvers/td3.ml | 26 +++++++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/src/solvers/td3.ml b/src/solvers/td3.ml index 2ed6cb80b0..30440e21f0 100644 --- a/src/solvers/td3.ml +++ b/src/solvers/td3.ml @@ -916,13 +916,33 @@ module WP = ) | GFun (fd, _) -> ignore (Pretty.printf "%a:\n" CilType.Fundec.pretty fd); + ignore (Pretty.printf " entry:\n"); let get x = try HM.find rho x with Not_found -> S.Dom.bot () in - (* let node: Node.t = FunctionEntry fd in *) - let node: Node.t = Statement (Cilfacade.getFirstStmt fd) in + let node: Node.t = FunctionEntry fd in S.iter_vars get (Node node) (fun v -> let d = get v in if not (S.Dom.is_bot d) then - ignore (Pretty.printf " %a: %a\n" S.Var.pretty_trace v S.Dom.pretty d) + ignore (Pretty.printf " %a: %a\n" S.Var.pretty_trace v S.Dom.pretty d) + ); + List.iter (fun stmt -> + ignore (Pretty.printf "%a:\n" CilType.Fundec.pretty fd); + ignore (Pretty.printf " %a:\n" Cilfacade.stmt_pretty_short stmt); + let get x = try HM.find rho x with Not_found -> S.Dom.bot () in + let node: Node.t = Statement stmt in + S.iter_vars get (Node node) (fun v -> + let d = get v in + if not (S.Dom.is_bot d) then + ignore (Pretty.printf " %a: %a\n" S.Var.pretty_trace v S.Dom.pretty d) + ) + ) fd.sallstmts; + ignore (Pretty.printf "%a:\n" CilType.Fundec.pretty fd); + ignore (Pretty.printf " return:\n"); + let get x = try HM.find rho x with Not_found -> S.Dom.bot () in + let node: Node.t = Function fd in + S.iter_vars get (Node node) (fun v -> + let d = get v in + if not (S.Dom.is_bot d) then + ignore (Pretty.printf " %a: %a\n" S.Var.pretty_trace v S.Dom.pretty d) ) | _ -> () ); From 9dad135410b9f0954573baecd46201768f1fadad Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 19 Jan 2022 17:59:09 +0200 Subject: [PATCH 191/402] Fix contexts for main function --- src/framework/constraints.ml | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/framework/constraints.ml b/src/framework/constraints.ml index 827ea9a006..d6a4c50abe 100644 --- a/src/framework/constraints.ml +++ b/src/framework/constraints.ml @@ -520,7 +520,6 @@ struct | fd -> let c = S.context fd d in sidel (FunctionEntry fd, c) d; - side_context sideg fd c; ignore (getl (Function fd, c)) | exception Not_found -> (* unknown function *) @@ -599,6 +598,10 @@ struct common_join ctx d !r !spawns let tf_entry var edge prev_node fd getl sidel getg sideg d = + (* Side effect function context here instead of at sidel to FunctionEntry, + because otherwise context for main functions (entrystates) will be missing or pruned during postsolving. *) + let c: unit -> S.C.t = snd var |> Obj.obj in + side_context sideg fd (c ()); let ctx, r, spawns = common_ctx var edge prev_node d getl sidel getg sideg in common_join ctx (S.body ctx fd) !r !spawns @@ -630,7 +633,7 @@ struct in let paths = S.enter ctx lv f args in let paths = List.map (fun (c,v) -> (c, S.context f v, v)) paths in - List.iter (fun (c,fc,v) -> if not (S.D.is_bot v) then (sidel (FunctionEntry f, fc) v; side_context sideg f fc)) paths; + List.iter (fun (c,fc,v) -> if not (S.D.is_bot v) then sidel (FunctionEntry f, fc) v) paths; let paths = List.map (fun (c,fc,v) -> (c, fc, if S.D.is_bot v then v else getl (Function f, fc))) paths in let paths = List.filter (fun (c,fc,v) -> not (D.is_bot v)) paths in if M.tracing then M.traceli "combine" "combining\n"; From 5ea0bdd9ac9735709cb50e4118ee01d2bfd867d2 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 19 Jan 2022 17:59:54 +0200 Subject: [PATCH 192/402] Refactor simulated global invariant in Control to use EQSys instead of Spec --- src/framework/control.ml | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/src/framework/control.ml b/src/framework/control.ml index 9b7cd1798c..68c5ef75a5 100644 --- a/src/framework/control.ml +++ b/src/framework/control.ml @@ -208,15 +208,14 @@ struct (* Simulate globals before analysis. *) (* TODO: make extern/global inits part of constraint system so all of this would be unnecessary. *) let gh = GHT.create 13 in - let getg v = GHT.find_default gh (EQSys.GVar.spec v) (EQSys.G.create_spec (Spec.G.bot ())) in + let getg v = GHT.find_default gh v (EQSys.G.bot ()) in let sideg v d = - let v' = EQSys.GVar.spec v in - if M.tracing then M.trace "global_inits" "sideg %a = %a\n" Spec.V.pretty v Spec.G.pretty d; - GHT.replace gh v' (EQSys.G.create_spec (Spec.G.join (EQSys.G.spec (getg v)) d)) + if M.tracing then M.trace "global_inits" "sideg %a = %a\n" EQSys.GVar.pretty v EQSys.G.pretty d; + GHT.replace gh v (EQSys.G.join (getg v) d) in (* Old-style global function for context. * This indirectly prevents global initializers from depending on each others' global side effects, which would require proper solving. *) - let getg v = Spec.G.bot () in + let getg v = EQSys.G.bot () in (* analyze cil's global-inits function to get a starting state *) let do_global_inits (file: file) : Spec.D.t * fundec list = @@ -229,12 +228,12 @@ struct ; context = (fun () -> ctx_failwith "Global initializers have no context.") ; edge = MyCFG.Skip ; local = Spec.D.top () - ; global = getg + ; global = (fun g -> EQSys.G.spec (getg (EQSys.GVar.spec g))) ; presub = [] ; postsub = [] ; spawn = (fun _ -> failwith "Global initializers should never spawn threads. What is going on?") ; split = (fun _ -> failwith "Global initializers trying to split paths.") - ; sideg = sideg + ; sideg = (fun g d -> sideg (EQSys.GVar.spec g) (EQSys.G.create_spec d)) ; assign = (fun ?name _ -> failwith "Global initializers trying to assign.") } in @@ -327,12 +326,12 @@ struct ; context = (fun () -> ctx_failwith "enter_func has no context.") ; edge = MyCFG.Skip ; local = st - ; global = getg + ; global = (fun g -> EQSys.G.spec (getg (EQSys.GVar.spec g))) ; presub = [] ; postsub = [] ; spawn = (fun _ -> failwith "Bug1: Using enter_func for toplevel functions with 'otherstate'.") ; split = (fun _ -> failwith "Bug2: Using enter_func for toplevel functions with 'otherstate'.") - ; sideg = sideg + ; sideg = (fun g d -> sideg (EQSys.GVar.spec g) (EQSys.G.create_spec d)) ; assign = (fun ?name _ -> failwith "Bug4: Using enter_func for toplevel functions with 'otherstate'.") } in @@ -362,12 +361,12 @@ struct ; context = (fun () -> ctx_failwith "enter_func has no context.") ; edge = MyCFG.Skip ; local = st - ; global = getg + ; global = (fun g -> EQSys.G.spec (getg (EQSys.GVar.spec g))) ; presub = [] ; postsub = [] ; spawn = (fun _ -> failwith "Bug1: Using enter_func for toplevel functions with 'otherstate'.") ; split = (fun _ -> failwith "Bug2: Using enter_func for toplevel functions with 'otherstate'.") - ; sideg = sideg + ; sideg = (fun g d -> sideg (EQSys.GVar.spec g) (EQSys.G.create_spec d)) ; assign = (fun ?name _ -> failwith "Bug4: Using enter_func for toplevel functions with 'otherstate'.") } in From edada3a41cfc1f5fd09a45c4be18e568bf6eccd7 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 20 Jan 2022 11:36:04 +0200 Subject: [PATCH 193/402] Add fundec override to Node var query --- src/framework/constraints.ml | 10 +++++----- src/framework/varQuery.ml | 2 +- src/solvers/td3.ml | 6 +++--- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/framework/constraints.ml b/src/framework/constraints.ml index d6a4c50abe..bd574aa3eb 100644 --- a/src/framework/constraints.ml +++ b/src/framework/constraints.ml @@ -782,11 +782,11 @@ struct S.query ctx (IterSysVars (vq, f)); match vq with - | Node n -> - let fd = Node.find_fundec n in + | Node {node; fundec} -> + let fd = Option.default_delayed (fun () -> Node.find_fundec node) fundec in let cs = G.contexts (getg (GVar.contexts fd)) in G.CSet.iter (fun c -> - fl (n, c) + fl (node, c) ) cs | _ -> () @@ -1169,8 +1169,8 @@ struct S.query (conv ctx) (IterSysVars (vq, vf')); begin match vq with - | Node n -> - vf (Obj.repr (V.node n)) + | Node {node; _} -> + vf (Obj.repr (V.node node)) | _ -> () end diff --git a/src/framework/varQuery.ml b/src/framework/varQuery.ml index 02cf9c34cf..b53a870d7f 100644 --- a/src/framework/varQuery.ml +++ b/src/framework/varQuery.ml @@ -1,6 +1,6 @@ type t = | Global of CilType.Varinfo.t - | Node of Node.t + | Node of {node: Node.t; fundec: CilType.Fundec.t option} (* TODO: add Function *) [@@deriving ord] diff --git a/src/solvers/td3.ml b/src/solvers/td3.ml index 30440e21f0..704092b80d 100644 --- a/src/solvers/td3.ml +++ b/src/solvers/td3.ml @@ -919,7 +919,7 @@ module WP = ignore (Pretty.printf " entry:\n"); let get x = try HM.find rho x with Not_found -> S.Dom.bot () in let node: Node.t = FunctionEntry fd in - S.iter_vars get (Node node) (fun v -> + S.iter_vars get (Node {node; fundec=Some fd}) (fun v -> let d = get v in if not (S.Dom.is_bot d) then ignore (Pretty.printf " %a: %a\n" S.Var.pretty_trace v S.Dom.pretty d) @@ -929,7 +929,7 @@ module WP = ignore (Pretty.printf " %a:\n" Cilfacade.stmt_pretty_short stmt); let get x = try HM.find rho x with Not_found -> S.Dom.bot () in let node: Node.t = Statement stmt in - S.iter_vars get (Node node) (fun v -> + S.iter_vars get (Node {node; fundec=Some fd}) (fun v -> let d = get v in if not (S.Dom.is_bot d) then ignore (Pretty.printf " %a: %a\n" S.Var.pretty_trace v S.Dom.pretty d) @@ -939,7 +939,7 @@ module WP = ignore (Pretty.printf " return:\n"); let get x = try HM.find rho x with Not_found -> S.Dom.bot () in let node: Node.t = Function fd in - S.iter_vars get (Node node) (fun v -> + S.iter_vars get (Node {node; fundec=Some fd}) (fun v -> let d = get v in if not (S.Dom.is_bot d) then ignore (Pretty.printf " %a: %a\n" S.Var.pretty_trace v S.Dom.pretty d) From fda86cc1d8d55508dd04f15cc6ef929acb056af7 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 20 Jan 2022 11:39:29 +0200 Subject: [PATCH 194/402] Use iter_vars for deleting old nodes incrementally --- src/solvers/td3.ml | 50 +++++++++++++++++++++++++++++++++++----------- 1 file changed, 38 insertions(+), 12 deletions(-) diff --git a/src/solvers/td3.ml b/src/solvers/td3.ml index 704092b80d..dd514a65d4 100644 --- a/src/solvers/td3.ml +++ b/src/solvers/td3.ml @@ -630,27 +630,48 @@ module WP = ); (* We remove all unknowns for program points in changed or removed functions from rho, stable, infl and wpoint *) - (* TODO: don't use string-based nodes, make marked_for_deletion of type unit (Hashtbl.Make (Node)).t *) - let add_nodes_of_fun (functions: fundec list) (nodes) withEntry = + let marked_for_deletion = HM.create 103 in + + let mark_node f node = + let get x = try HM.find rho x with Not_found -> S.Dom.bot () in + S.iter_vars get (Node {node; fundec = Some f}) (fun v -> + HM.replace marked_for_deletion v () + ) + in + let add_nodes_of_fun (functions: fundec list) withEntry = let add_stmts (f: fundec) = - List.iter (fun s -> Hashtbl.replace nodes (Node.show_id (Statement s)) ()) (f.sallstmts) + List.iter (fun s -> + mark_node f (Statement s) + ) f.sallstmts in - List.iter (fun f -> if withEntry then Hashtbl.replace nodes (Node.show_id (FunctionEntry f)) (); Hashtbl.replace nodes (Node.show_id (Function f)) (); add_stmts f; Hashtbl.replace nodes (string_of_int (CfgTools.get_pseudo_return_id f)) ()) functions; + List.iter (fun f -> + if withEntry then + mark_node f (FunctionEntry f); + mark_node f (Function f); + add_stmts f; + (* TODO: pseudo return *) + (* HM.replace nodes (string_of_int (CfgTools.get_pseudo_return_id f)) () *) + ) functions; in - let marked_for_deletion = Hashtbl.create 103 in - add_nodes_of_fun changed_funs marked_for_deletion (not (GobConfig.get_bool "incremental.reluctant.on")); - add_nodes_of_fun removed_funs marked_for_deletion true; + add_nodes_of_fun changed_funs (not (GobConfig.get_bool "incremental.reluctant.on")); + add_nodes_of_fun removed_funs true; (* it is necessary to remove all unknowns for changed pseudo-returns because they have static ids *) let add_pseudo_return f un = let pid = CfgTools.get_pseudo_return_id f in let is_pseudo_return n = match n with MyCFG.Statement s -> s.sid = pid | _ -> false in - if not (List.exists (fun x -> is_pseudo_return @@ fst @@ x) un) - then Hashtbl.replace marked_for_deletion (string_of_int pid) () in - List.iter (fun (f,_,un) -> Hashtbl.replace marked_for_deletion (Node.show_id (Function f)) (); add_pseudo_return f un) part_changed_funs; + () + (* TODO: pseudo return *) + (* if not (List.exists (fun x -> is_pseudo_return @@ fst @@ x) un) then + HM.replace marked_for_deletion (string_of_int pid) () *) + in + List.iter (fun (f,_,un) -> + mark_node f (Function f); + add_pseudo_return f un + ) part_changed_funs; print_endline "Removing data for changed and removed functions..."; - let delete_marked s = HM.filteri_inplace (fun k _ -> not (Hashtbl.mem marked_for_deletion (S.Var.var_id k))) s in (* TODO: don't use string-based nodes *) + let delete_marked s = HM.filteri_inplace (fun k _ -> not (HM.mem marked_for_deletion k)) s in delete_marked rho; delete_marked infl; delete_marked wpoint; @@ -660,7 +681,12 @@ module WP = (* restarts old copies of functions and their (removed) side effects *) print_endline "Destabilizing sides of changed functions, primary old nodes and removed functions ..."; let stable_copy = HM.copy stable in (* use copy because destabilize modifies stable *) - HM.iter (fun k _ -> if Hashtbl.mem marked_for_deletion (S.Var.var_id k) then (ignore (Pretty.printf "marked %a\n" S.Var.pretty_trace k); destabilize k)) stable_copy; (* TODO: don't use string-based nodes *) + HM.iter (fun k _ -> + if HM.mem marked_for_deletion k then ( + ignore (Pretty.printf "marked %a\n" S.Var.pretty_trace k); + destabilize k + ) + ) stable_copy ); let restart_and_destabilize x = (* destabilize_with_side doesn't restart x itself *) From 96608af5abbf3456787ba9deed4d02c67cac1589 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 20 Jan 2022 11:48:07 +0200 Subject: [PATCH 195/402] Add back TD3 incremental pseudo return marking --- src/solvers/td3.ml | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/solvers/td3.ml b/src/solvers/td3.ml index dd514a65d4..5285e936da 100644 --- a/src/solvers/td3.ml +++ b/src/solvers/td3.ml @@ -638,6 +638,10 @@ module WP = HM.replace marked_for_deletion v () ) in + let dummy_pseudo_return_node f = + (* not the same as in CFG, but compares equal because of sid *) + Node.Statement ({Cil.dummyStmt with sid = CfgTools.get_pseudo_return_id f}) + in let add_nodes_of_fun (functions: fundec list) withEntry = let add_stmts (f: fundec) = List.iter (fun s -> @@ -649,8 +653,7 @@ module WP = mark_node f (FunctionEntry f); mark_node f (Function f); add_stmts f; - (* TODO: pseudo return *) - (* HM.replace nodes (string_of_int (CfgTools.get_pseudo_return_id f)) () *) + mark_node f (dummy_pseudo_return_node f) ) functions; in @@ -658,12 +661,9 @@ module WP = add_nodes_of_fun removed_funs true; (* it is necessary to remove all unknowns for changed pseudo-returns because they have static ids *) let add_pseudo_return f un = - let pid = CfgTools.get_pseudo_return_id f in - let is_pseudo_return n = match n with MyCFG.Statement s -> s.sid = pid | _ -> false in - () - (* TODO: pseudo return *) - (* if not (List.exists (fun x -> is_pseudo_return @@ fst @@ x) un) then - HM.replace marked_for_deletion (string_of_int pid) () *) + let pseudo = dummy_pseudo_return_node f in + if not (List.exists (Node.equal pseudo % fst) un) then + mark_node f (dummy_pseudo_return_node f) in List.iter (fun (f,_,un) -> mark_node f (Function f); From f1bc06997e7efce30d5a2b0abe4a1e58e7dff6a4 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 20 Jan 2022 11:52:17 +0200 Subject: [PATCH 196/402] Flip TD3 incremental marking to iterate over marked --- src/solvers/td3.ml | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/solvers/td3.ml b/src/solvers/td3.ml index 5285e936da..800c4a0e98 100644 --- a/src/solvers/td3.ml +++ b/src/solvers/td3.ml @@ -671,7 +671,7 @@ module WP = ) part_changed_funs; print_endline "Removing data for changed and removed functions..."; - let delete_marked s = HM.filteri_inplace (fun k _ -> not (HM.mem marked_for_deletion k)) s in + let delete_marked s = HM.iter (fun k _ -> HM.remove s k) marked_for_deletion in delete_marked rho; delete_marked infl; delete_marked wpoint; @@ -680,13 +680,12 @@ module WP = if restart_sided then ( (* restarts old copies of functions and their (removed) side effects *) print_endline "Destabilizing sides of changed functions, primary old nodes and removed functions ..."; - let stable_copy = HM.copy stable in (* use copy because destabilize modifies stable *) HM.iter (fun k _ -> - if HM.mem marked_for_deletion k then ( + if HM.mem stable k then ( ignore (Pretty.printf "marked %a\n" S.Var.pretty_trace k); destabilize k ) - ) stable_copy + ) marked_for_deletion ); let restart_and_destabilize x = (* destabilize_with_side doesn't restart x itself *) From 7db0fe37af344b29aa87e655a1b876e96c5d7f73 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 20 Jan 2022 12:29:56 +0200 Subject: [PATCH 197/402] Fix FromSpec collected contexts relifting --- src/domains/setDomain.ml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/domains/setDomain.ml b/src/domains/setDomain.ml index 3d9b55dfd3..dde0e778dc 100644 --- a/src/domains/setDomain.ml +++ b/src/domains/setDomain.ml @@ -119,6 +119,8 @@ struct let hash x = fold (fun x y -> y + Base.hash x) x 0 + let relift x = map Base.relift x + let pretty_diff () ((x:t),(y:t)): Pretty.doc = if leq x y then dprintf "%s: These are fine!" (name ()) else if is_bot y then dprintf "%s: %a instead of bot" (name ()) pretty x else begin From 9aa47a85c41ed04c9b9a863e65cbc776c674ae99 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 20 Jan 2022 12:33:23 +0200 Subject: [PATCH 198/402] Use iter_vars for destabilizing nodes incrementally --- src/solvers/td3.ml | 58 ++++++++++++++++++++++++++++------------------ 1 file changed, 36 insertions(+), 22 deletions(-) diff --git a/src/solvers/td3.ml b/src/solvers/td3.ml index 800c4a0e98..23ea489729 100644 --- a/src/solvers/td3.ml +++ b/src/solvers/td3.ml @@ -606,38 +606,52 @@ module WP = let part_changed_funs = filter_map (fun c -> match c.old, c.diff with GFun (f,l), Some nd -> Some (f,nd.primObsoleteNodes,nd.unchangedNodes) | _ -> None) S.increment.changes.changed in let prim_old_nodes_ids = Set.of_list (List.concat_map (fun (_,pn,_) -> List.map Node.show_id pn) part_changed_funs) in let removed_funs = filter_map (fun g -> match g with GFun (f,l) -> Some f | _ -> None) S.increment.changes.removed in - (* TODO: don't use string-based nodes, make obsolete of type Node.t BatSet.t *) - let obsolete_ret = Set.union (Set.of_list (List.map (fun f -> Node.show_id (Function f)) changed_funs)) - (Set.of_list (List.map (fun (f,_,_) -> Node.show_id (Function f)) part_changed_funs)) in - let obsolete_entry = Set.of_list (List.map (fun f -> Node.show_id (FunctionEntry f)) changed_funs) in + + let mark_node hm f node = + let get x = try HM.find rho x with Not_found -> S.Dom.bot () in + S.iter_vars get (Node {node; fundec = Some f}) (fun v -> + HM.replace hm v () + ) + in + + let obsolete_ret = HM.create 103 in + let obsolete_entry = HM.create 103 in + List.iter (fun f -> + mark_node obsolete_entry f (FunctionEntry f); + mark_node obsolete_ret f (Function f); + ) changed_funs; + List.iter (fun (f, _, _) -> + mark_node obsolete_ret f (Function f); + ) part_changed_funs; List.iter (fun a -> print_endline ("Completely changed function: " ^ a.svar.vname)) changed_funs; List.iter (fun (f,_,_) -> print_endline ("Partially changed function: " ^ (f.svar.vname))) part_changed_funs; List.iter (fun f -> print_endline ("Removed function: " ^ (f.svar.vname))) removed_funs; - let old_ret = Hashtbl.create 103 in + let old_ret = Hashtbl.create 103 in (* TODO: use HM *) if GobConfig.get_bool "incremental.reluctant.on" then ( (* save entries of changed functions in rho for the comparison whether the result has changed after a function specific solve *) - HM.iter (fun k v -> if Set.mem (S.Var.var_id k) obsolete_ret then ( (* TODO: don't use string-based nodes *) - let old_rho = HM.find rho k in - let old_infl = HM.find_default infl k VS.empty in - Hashtbl.replace old_ret k (old_rho, old_infl))) rho; + HM.iter (fun k v -> + if HM.mem obsolete_ret k then ( + let old_rho = HM.find rho k in + let old_infl = HM.find_default infl k VS.empty in + Hashtbl.replace old_ret k (old_rho, old_infl) + ) + ) rho; ) else ( (* If reluctant destabilization is turned off we need to destabilize all nodes in completely changed functions and the primary obsolete nodes of partly changed functions *) print_endline "Destabilizing changed functions and primary old nodes ..."; - HM.iter (fun k _ -> if Set.mem (S.Var.var_id k) obsolete_entry || Set.mem (S.Var.var_id k) prim_old_nodes_ids then destabilize k) stable; (* TODO: don't use string-based nodes *) + let stable_copy = HM.copy stable in + HM.iter (fun k _ -> + if HM.mem obsolete_entry k || Set.mem (S.Var.var_id k) prim_old_nodes_ids then (* TODO: don't use string-based nodes *) + destabilize k + ) stable_copy; ); (* We remove all unknowns for program points in changed or removed functions from rho, stable, infl and wpoint *) let marked_for_deletion = HM.create 103 in - let mark_node f node = - let get x = try HM.find rho x with Not_found -> S.Dom.bot () in - S.iter_vars get (Node {node; fundec = Some f}) (fun v -> - HM.replace marked_for_deletion v () - ) - in let dummy_pseudo_return_node f = (* not the same as in CFG, but compares equal because of sid *) Node.Statement ({Cil.dummyStmt with sid = CfgTools.get_pseudo_return_id f}) @@ -645,15 +659,15 @@ module WP = let add_nodes_of_fun (functions: fundec list) withEntry = let add_stmts (f: fundec) = List.iter (fun s -> - mark_node f (Statement s) + mark_node marked_for_deletion f (Statement s) ) f.sallstmts in List.iter (fun f -> if withEntry then - mark_node f (FunctionEntry f); - mark_node f (Function f); + mark_node marked_for_deletion f (FunctionEntry f); + mark_node marked_for_deletion f (Function f); add_stmts f; - mark_node f (dummy_pseudo_return_node f) + mark_node marked_for_deletion f (dummy_pseudo_return_node f) ) functions; in @@ -663,10 +677,10 @@ module WP = let add_pseudo_return f un = let pseudo = dummy_pseudo_return_node f in if not (List.exists (Node.equal pseudo % fst) un) then - mark_node f (dummy_pseudo_return_node f) + mark_node marked_for_deletion f (dummy_pseudo_return_node f) in List.iter (fun (f,_,un) -> - mark_node f (Function f); + mark_node marked_for_deletion f (Function f); add_pseudo_return f un ) part_changed_funs; From e1c9f5a65f5d365e37fff87448fc6d7a1949fff0 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 20 Jan 2022 12:37:22 +0200 Subject: [PATCH 199/402] Use iter_vars for destabilizing primary old nodes incrementally --- src/solvers/td3.ml | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/solvers/td3.ml b/src/solvers/td3.ml index 23ea489729..51246dc648 100644 --- a/src/solvers/td3.ml +++ b/src/solvers/td3.ml @@ -604,7 +604,6 @@ module WP = in let changed_funs = filter_map (fun c -> match c.old, c.diff with GFun (f,l), None -> Some f | _ -> None) S.increment.changes.changed in let part_changed_funs = filter_map (fun c -> match c.old, c.diff with GFun (f,l), Some nd -> Some (f,nd.primObsoleteNodes,nd.unchangedNodes) | _ -> None) S.increment.changes.changed in - let prim_old_nodes_ids = Set.of_list (List.concat_map (fun (_,pn,_) -> List.map Node.show_id pn) part_changed_funs) in let removed_funs = filter_map (fun g -> match g with GFun (f,l) -> Some f | _ -> None) S.increment.changes.removed in let mark_node hm f node = @@ -616,11 +615,15 @@ module WP = let obsolete_ret = HM.create 103 in let obsolete_entry = HM.create 103 in + let obsolete_prim = HM.create 103 in List.iter (fun f -> mark_node obsolete_entry f (FunctionEntry f); mark_node obsolete_ret f (Function f); ) changed_funs; - List.iter (fun (f, _, _) -> + List.iter (fun (f, pn, _) -> + List.iter (fun n -> + mark_node obsolete_prim f n + ) pn; mark_node obsolete_ret f (Function f); ) part_changed_funs; @@ -644,7 +647,7 @@ module WP = print_endline "Destabilizing changed functions and primary old nodes ..."; let stable_copy = HM.copy stable in HM.iter (fun k _ -> - if HM.mem obsolete_entry k || Set.mem (S.Var.var_id k) prim_old_nodes_ids then (* TODO: don't use string-based nodes *) + if HM.mem obsolete_entry k || HM.mem obsolete_prim k then destabilize k ) stable_copy; ); From 8b8d3885ec9d23f35e26018e2959494863d13d27 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 20 Jan 2022 12:40:42 +0200 Subject: [PATCH 200/402] Flip TD3 incremental destabilize to iterate over obsolete --- src/solvers/td3.ml | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/solvers/td3.ml b/src/solvers/td3.ml index 51246dc648..2cf8f4d8ee 100644 --- a/src/solvers/td3.ml +++ b/src/solvers/td3.ml @@ -635,21 +635,24 @@ module WP = if GobConfig.get_bool "incremental.reluctant.on" then ( (* save entries of changed functions in rho for the comparison whether the result has changed after a function specific solve *) HM.iter (fun k v -> - if HM.mem obsolete_ret k then ( + if HM.mem rho k then ( let old_rho = HM.find rho k in let old_infl = HM.find_default infl k VS.empty in Hashtbl.replace old_ret k (old_rho, old_infl) ) - ) rho; + ) obsolete_ret; ) else ( (* If reluctant destabilization is turned off we need to destabilize all nodes in completely changed functions and the primary obsolete nodes of partly changed functions *) print_endline "Destabilizing changed functions and primary old nodes ..."; - let stable_copy = HM.copy stable in HM.iter (fun k _ -> - if HM.mem obsolete_entry k || HM.mem obsolete_prim k then + if HM.mem stable k then destabilize k - ) stable_copy; + ) obsolete_entry; + HM.iter (fun k _ -> + if HM.mem stable k then + destabilize k + ) obsolete_prim; ); (* We remove all unknowns for program points in changed or removed functions from rho, stable, infl and wpoint *) From d016c96849a93b09d77373bf728b87a5947ecdf9 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 20 Jan 2022 12:42:17 +0200 Subject: [PATCH 201/402] Fix polymorphic Hashtbl in TD3 reluctant destabilization --- src/solvers/td3.ml | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/solvers/td3.ml b/src/solvers/td3.ml index 2cf8f4d8ee..2ae1775ad6 100644 --- a/src/solvers/td3.ml +++ b/src/solvers/td3.ml @@ -631,14 +631,14 @@ module WP = List.iter (fun (f,_,_) -> print_endline ("Partially changed function: " ^ (f.svar.vname))) part_changed_funs; List.iter (fun f -> print_endline ("Removed function: " ^ (f.svar.vname))) removed_funs; - let old_ret = Hashtbl.create 103 in (* TODO: use HM *) + let old_ret = HM.create 103 in if GobConfig.get_bool "incremental.reluctant.on" then ( (* save entries of changed functions in rho for the comparison whether the result has changed after a function specific solve *) HM.iter (fun k v -> if HM.mem rho k then ( let old_rho = HM.find rho k in let old_infl = HM.find_default infl k VS.empty in - Hashtbl.replace old_ret k (old_rho, old_infl) + HM.replace old_ret k (old_rho, old_infl) ) ) obsolete_ret; ) else ( @@ -754,8 +754,7 @@ module WP = (* solve on the return node of changed functions. Only destabilize the function's return node if the analysis result changed *) print_endline "Separately solving changed functions..."; let op = if GobConfig.get_string "incremental.reluctant.compare" = "leq" then S.Dom.leq else S.Dom.equal in - Hashtbl.iter ( - fun x (old_rho, old_infl) -> + HM.iter (fun x (old_rho, old_infl) -> ignore @@ Pretty.printf "test for %a\n" Node.pretty_trace (S.Var.node x); ignore (solve x Widen false); (* TODO: use returned changed for comparison? *) if not (op (HM.find rho x) old_rho) then ( @@ -764,7 +763,7 @@ module WP = destabilize x; HM.replace stable x () ) - ) old_ret; + ) old_ret; print_endline "Final solve..." ); From 6c0502d979fcb1c77ec5f8663b18fd969f895400 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 20 Jan 2022 12:54:03 +0200 Subject: [PATCH 202/402] Clean up incremental functions in TD3 --- src/solvers/td3.ml | 29 ++++++++++++++++++++--------- 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/src/solvers/td3.ml b/src/solvers/td3.ml index 2ae1775ad6..39a8362893 100644 --- a/src/solvers/td3.ml +++ b/src/solvers/td3.ml @@ -599,12 +599,27 @@ module WP = else destabilize_normal; - let filter_map f l = - List.fold_left (fun acc el -> match f el with Some x -> x::acc | _ -> acc) [] l + let changed_funs = List.filter_map (function + | {old = GFun (f, _); diff = None; _} -> + print_endline ("Completely changed function: " ^ f.svar.vname); + Some f + | _ -> None + ) S.increment.changes.changed + in + let part_changed_funs = List.filter_map (function + | {old = GFun (f, _); diff = Some nd; _} -> + print_endline ("Partially changed function: " ^ f.svar.vname); + Some (f, nd.primObsoleteNodes, nd.unchangedNodes) + | _ -> None + ) S.increment.changes.changed + in + let removed_funs = List.filter_map (function + | GFun (f, _) -> + print_endline ("Removed function: " ^ f.svar.vname); + Some f + | _ -> None + ) S.increment.changes.removed in - let changed_funs = filter_map (fun c -> match c.old, c.diff with GFun (f,l), None -> Some f | _ -> None) S.increment.changes.changed in - let part_changed_funs = filter_map (fun c -> match c.old, c.diff with GFun (f,l), Some nd -> Some (f,nd.primObsoleteNodes,nd.unchangedNodes) | _ -> None) S.increment.changes.changed in - let removed_funs = filter_map (fun g -> match g with GFun (f,l) -> Some f | _ -> None) S.increment.changes.removed in let mark_node hm f node = let get x = try HM.find rho x with Not_found -> S.Dom.bot () in @@ -627,10 +642,6 @@ module WP = mark_node obsolete_ret f (Function f); ) part_changed_funs; - List.iter (fun a -> print_endline ("Completely changed function: " ^ a.svar.vname)) changed_funs; - List.iter (fun (f,_,_) -> print_endline ("Partially changed function: " ^ (f.svar.vname))) part_changed_funs; - List.iter (fun f -> print_endline ("Removed function: " ^ (f.svar.vname))) removed_funs; - let old_ret = HM.create 103 in if GobConfig.get_bool "incremental.reluctant.on" then ( (* save entries of changed functions in rho for the comparison whether the result has changed after a function specific solve *) From 4cbfbf44f4ee84e39f0ce72d9c26d7ce3f303178 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 20 Jan 2022 13:05:48 +0200 Subject: [PATCH 203/402] Fix dead branch indentation (PR #525) --- src/framework/constraints.ml | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/framework/constraints.ml b/src/framework/constraints.ml index 13277d2651..45e77ca979 100644 --- a/src/framework/constraints.ml +++ b/src/framework/constraints.ml @@ -1103,18 +1103,18 @@ struct | WarnGlobal g -> let g: V.t = Obj.obj g in begin match g with - | `Left g -> - S.query (conv ctx) (WarnGlobal (Obj.repr g)) - | `Right g -> - let em = G.node (ctx.global (V.node g)) in - EM.iter (fun exp tv -> - match tv with - | `Lifted tv -> - M.warn ~loc:(Node.location g) ~tags:[CWE (if tv then 571 else 570)] ~category:Deadcode "condition '%a' is always %B" d_exp exp tv - | `Bot (* all branches dead? can happen at our inserted Neg(1)-s because no Pos(1) *) - | `Top -> (* may be both true and false *) - () - ) em; + | `Left g -> + S.query (conv ctx) (WarnGlobal (Obj.repr g)) + | `Right g -> + let em = G.node (ctx.global (V.node g)) in + EM.iter (fun exp tv -> + match tv with + | `Lifted tv -> + M.warn ~loc:(Node.location g) ~tags:[CWE (if tv then 571 else 570)] ~category:Deadcode "condition '%a' is always %B" d_exp exp tv + | `Bot (* all branches dead? can happen at our inserted Neg(1)-s because no Pos(1) *) + | `Top -> (* may be both true and false *) + () + ) em; end | _ -> S.query (conv ctx) q From 26b3b878df75b8b297c060599577c859d0e9ac1f Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 20 Jan 2022 13:22:40 +0200 Subject: [PATCH 204/402] Document VarQuery --- src/analyses/apron/apronPriv.apron.ml | 2 +- src/analyses/basePriv.mli | 2 +- src/analyses/mCP.ml | 1 + src/domains/queries.ml | 2 +- src/framework/analyses.ml | 4 ++-- src/framework/constraints.ml | 6 +++++- src/framework/control.ml | 4 ++-- src/framework/varQuery.ml | 3 +-- src/solvers/td3.ml | 1 + 9 files changed, 15 insertions(+), 10 deletions(-) diff --git a/src/analyses/apron/apronPriv.apron.ml b/src/analyses/apron/apronPriv.apron.ml index 20ec478ea3..9905cfc33f 100644 --- a/src/analyses/apron/apronPriv.apron.ml +++ b/src/analyses/apron/apronPriv.apron.ml @@ -39,7 +39,7 @@ module type S = val thread_join: Q.ask -> (V.t -> G.t) -> Cil.exp -> apron_components_t -> apron_components_t val thread_return: Q.ask -> (V.t -> G.t) -> (V.t -> G.t -> unit) -> ThreadIdDomain.Thread.t -> apron_components_t -> apron_components_t - val iter_sys_vars: (V.t -> G.t) -> VarQuery.t -> V.t VarQuery.f -> unit + val iter_sys_vars: (V.t -> G.t) -> VarQuery.t -> V.t VarQuery.f -> unit (** [Queries.IterSysVars] for base. *) val init: unit -> unit val finalize: unit -> unit diff --git a/src/analyses/basePriv.mli b/src/analyses/basePriv.mli index 1dc413ebfc..e212140ee4 100644 --- a/src/analyses/basePriv.mli +++ b/src/analyses/basePriv.mli @@ -21,7 +21,7 @@ sig val escape: Queries.ask -> (V.t -> G.t) -> (V.t -> G.t -> unit) -> BaseDomain.BaseComponents (D).t -> EscapeDomain.EscapedVars.t -> BaseDomain.BaseComponents (D).t val enter_multithreaded: Queries.ask -> (V.t -> G.t) -> (V.t -> G.t -> unit) -> BaseDomain.BaseComponents (D).t -> BaseDomain.BaseComponents (D).t val threadenter: Queries.ask -> BaseDomain.BaseComponents (D).t -> BaseDomain.BaseComponents (D).t - val iter_sys_vars: (V.t -> G.t) -> VarQuery.t -> V.t VarQuery.f -> unit + val iter_sys_vars: (V.t -> G.t) -> VarQuery.t -> V.t VarQuery.f -> unit (** [Queries.IterSysVars] for base. *) val init: unit -> unit val finalize: unit -> unit diff --git a/src/analyses/mCP.ml b/src/analyses/mCP.ml index d0dd1797d7..29c9d3e6e2 100644 --- a/src/analyses/mCP.ml +++ b/src/analyses/mCP.ml @@ -689,6 +689,7 @@ struct let (n, g): V.t = Obj.obj g in f ~q:(WarnGlobal (Obj.repr g)) (Result.top ()) (n, spec n, assoc n ctx.local) | Queries.IterSysVars (vq, fi) -> + (* IterSysVars is special: argument function is lifted for each analysis *) iter (fun ((n,(module S:MCPSpec),d) as t) -> let fi' x = fi (Obj.repr (v_of n x)) in let q' = Queries.IterSysVars (vq, fi') in diff --git a/src/domains/queries.ml b/src/domains/queries.ml index 6ec749a40e..8ce7eff9e4 100644 --- a/src/domains/queries.ml +++ b/src/domains/queries.ml @@ -97,7 +97,7 @@ type _ t = | CreatedThreads: ConcDomain.ThreadSet.t t | MustJoinedThreads: ConcDomain.MustThreadSet.t t | WarnGlobal: Obj.t -> Unit.t t (** Argument must be of corresponding [Spec.V.t]. *) - | IterSysVars: VarQuery.t * (Obj.t -> unit) -> Unit.t t + | IterSysVars: VarQuery.t * (Obj.t -> unit) -> Unit.t t (** [iter_vars] for [Constraints.FromSpec]. [Obj.t] represents [Spec.V.t]. *) type 'a result = 'a diff --git a/src/framework/analyses.ml b/src/framework/analyses.ml index 6f634e3b66..a1db4a3bf1 100644 --- a/src/framework/analyses.ml +++ b/src/framework/analyses.ml @@ -446,7 +446,7 @@ sig (** Data used for incremental analysis *) val increment : increment_data - val iter_vars: (v -> d) -> VarQuery.t -> (v -> unit) -> unit + val iter_vars: (v -> d) -> VarQuery.t -> v VarQuery.f -> unit end (** Any system of side-effecting equations over lattices. *) @@ -462,7 +462,7 @@ sig module G : Lattice.S val increment : increment_data val system : LVar.t -> ((LVar.t -> D.t) -> (LVar.t -> D.t -> unit) -> (GVar.t -> G.t) -> (GVar.t -> G.t -> unit) -> D.t) option - val iter_vars: (LVar.t -> D.t) -> (GVar.t -> G.t) -> VarQuery.t -> (LVar.t -> unit) -> (GVar.t -> unit) -> unit + val iter_vars: (LVar.t -> D.t) -> (GVar.t -> G.t) -> VarQuery.t -> LVar.t VarQuery.f -> GVar.t VarQuery.f -> unit end (** A solver is something that can translate a system into a solution (hash-table). diff --git a/src/framework/constraints.ml b/src/framework/constraints.ml index bd574aa3eb..c6d99103d6 100644 --- a/src/framework/constraints.ml +++ b/src/framework/constraints.ml @@ -760,6 +760,7 @@ struct Some tf let iter_vars getl getg vq fl fg = + (* vars for Spec *) let rec ctx = { ask = (fun (type a) (q: a Queries.t) -> S.query ctx q) ; emit = (fun _ -> failwith "Cannot \"emit\" in query context.") @@ -768,7 +769,7 @@ struct ; control_context = Obj.repr (fun () -> ctx_failwith "No context in query context.") ; context = (fun () -> ctx_failwith "No context in query context.") ; edge = MyCFG.Skip - ; local = S.startstate Cil.dummyFunDec.svar + ; local = S.startstate Cil.dummyFunDec.svar (* bot and top both silently raise and catch Deadcode in DeadcodeLifter *) ; global = (fun g -> G.spec (getg (GVar.spec g))) ; presub = [] ; postsub= [] @@ -781,6 +782,7 @@ struct let f v = fg (GVar.spec (Obj.obj v)) in S.query ctx (IterSysVars (vq, f)); + (* node vars for locals *) match vq with | Node {node; fundec} -> let fd = Option.default_delayed (fun () -> Node.find_fundec node) fundec in @@ -1165,9 +1167,11 @@ struct ) em; end | IterSysVars (vq, vf) -> + (* vars for S *) let vf' x = vf (Obj.repr (V.s (Obj.obj x))) in S.query (conv ctx) (IterSysVars (vq, vf')); + (* node vars for dead branches *) begin match vq with | Node {node; _} -> vf (Obj.repr (V.node node)) diff --git a/src/framework/control.ml b/src/framework/control.ml index 68c5ef75a5..f7a07756a5 100644 --- a/src/framework/control.ml +++ b/src/framework/control.ml @@ -617,9 +617,9 @@ struct } in match g with - | `Left g -> + | `Left g -> (* Spec global *) Spec.query ctx (WarnGlobal (Obj.repr g)) - | `Right _ -> + | `Right _ -> (* contexts global *) () in Stats.time "warn_global" (GHT.iter warn_global) gh; diff --git a/src/framework/varQuery.ml b/src/framework/varQuery.ml index b53a870d7f..d3c3a88a4f 100644 --- a/src/framework/varQuery.ml +++ b/src/framework/varQuery.ml @@ -1,7 +1,6 @@ type t = | Global of CilType.Varinfo.t - | Node of {node: Node.t; fundec: CilType.Fundec.t option} - (* TODO: add Function *) + | Node of {node: Node.t; fundec: CilType.Fundec.t option} (** Optional [fundec] override to allow querying old state in incremental. *) [@@deriving ord] type 'v f = 'v -> unit diff --git a/src/solvers/td3.ml b/src/solvers/td3.ml index 39a8362893..77636ab07c 100644 --- a/src/solvers/td3.ml +++ b/src/solvers/td3.ml @@ -960,6 +960,7 @@ module WP = print_data data "Data after postsolve"; + (* TODO: example debug output for queries, remove *) Cil.iterGlobals !Cilfacade.current_file (function | GVar (g, _, _) -> ignore (Pretty.printf "%a:\n" CilType.Varinfo.pretty g); From b6fc7fdce5e6714ad7003ebc9ee364117593d6f2 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 20 Jan 2022 13:51:47 +0200 Subject: [PATCH 205/402] Document some double global invariants --- src/analyses/accessAnalysis.ml | 18 +++++++++++------- src/analyses/base.ml | 4 ++++ src/framework/constraints.ml | 8 ++++++++ 3 files changed, 23 insertions(+), 7 deletions(-) diff --git a/src/analyses/accessAnalysis.ml b/src/analyses/accessAnalysis.ml index 74e8b76070..d0877f523b 100644 --- a/src/analyses/accessAnalysis.ml +++ b/src/analyses/accessAnalysis.ml @@ -17,6 +17,10 @@ struct module D = Lattice.Unit module C = Lattice.Unit + (* Two global invariants: + 1. (lval, type) -> accesses -- used for warnings + 2. varinfo -> set of (lval, type) -- used for IterSysVars Global *) + module V0 = Printable.Prod (Access.LVOpt) (Access.T) module V = struct @@ -245,17 +249,17 @@ struct | WarnGlobal g -> let g: V.t = Obj.obj g in begin match g with - | `Left g -> + | `Left g' -> (* accesses *) (* ignore (Pretty.printf "WarnGlobal %a\n" CilType.Varinfo.pretty g); *) - let pm = G.access (ctx.global (V.access g)) in - Access.print_accesses g pm; - Access.incr_summary safe vulnerable unsafe g pm - | `Right _ -> + let pm = G.access (ctx.global g) in + Access.print_accesses g' pm; + Access.incr_summary safe vulnerable unsafe g' pm + | `Right _ -> (* vars *) () end | IterSysVars (Global g, vf) -> - V0Set.iter (fun (lv_opt, ty) -> - vf (Obj.repr (V.access (lv_opt, ty))) + V0Set.iter (fun v -> + vf (Obj.repr (V.access v)) ) (G.vars (ctx.global (V.vars g))) | _ -> Queries.Result.top q diff --git a/src/analyses/base.ml b/src/analyses/base.ml index a0df23d62a..457c3b52cb 100644 --- a/src/analyses/base.ml +++ b/src/analyses/base.ml @@ -38,6 +38,10 @@ struct module D = Dom module C = Dom + (* Two global invariants: + 1. Priv.V -> Priv.G -- used for Priv + 2. thread -> VD -- used for thread returns *) + module V = struct include Printable.Either (Priv.V) (ThreadIdDomain.Thread) diff --git a/src/framework/constraints.ml b/src/framework/constraints.ml index c6d99103d6..2c2c2029b8 100644 --- a/src/framework/constraints.ml +++ b/src/framework/constraints.ml @@ -472,6 +472,10 @@ struct module D = S.D module G = GVarG (S.G) (S.C) + (* Two global invariants: + 1. S.V -> S.G -- used for Spec + 2. fundec -> set of S.C -- used for IterSysVars Node *) + (* Dummy module. No incremental analysis supported here*) let increment = I.increment @@ -1108,6 +1112,10 @@ struct let name () = "DeadBranch (" ^ S.name () ^ ")" + (* Two global invariants: + 1. S.V -> S.G -- used for S + 2. node -> (exp -> flat bool) -- used for warnings *) + module V = struct include Printable.Either (S.V) (Node) From 99672db2884ea75e0dec86d9aa82f49a90b9aca1 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 20 Jan 2022 13:55:44 +0200 Subject: [PATCH 206/402] Rename in Queries --- src/domains/queries.ml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/domains/queries.ml b/src/domains/queries.ml index 8ce7eff9e4..3b5854839e 100644 --- a/src/domains/queries.ml +++ b/src/domains/queries.ml @@ -97,7 +97,7 @@ type _ t = | CreatedThreads: ConcDomain.ThreadSet.t t | MustJoinedThreads: ConcDomain.MustThreadSet.t t | WarnGlobal: Obj.t -> Unit.t t (** Argument must be of corresponding [Spec.V.t]. *) - | IterSysVars: VarQuery.t * (Obj.t -> unit) -> Unit.t t (** [iter_vars] for [Constraints.FromSpec]. [Obj.t] represents [Spec.V.t]. *) + | IterSysVars: VarQuery.t * Obj.t VarQuery.f -> Unit.t t (** [iter_vars] for [Constraints.FromSpec]. [Obj.t] represents [Spec.V.t]. *) type 'a result = 'a @@ -288,7 +288,7 @@ struct | Any (IsMultiple v1), Any (IsMultiple v2) -> CilType.Varinfo.compare v1 v2 | Any (EvalThread e1), Any (EvalThread e2) -> CilType.Exp.compare e1 e2 | Any (WarnGlobal vi1), Any (WarnGlobal vi2) -> compare (Hashtbl.hash vi1) (Hashtbl.hash vi2) - | Any (IterSysVars (vq1, f1)), Any (IterSysVars (vq2, f2)) -> VarQuery.compare vq1 vq2 (* not comparing fs *) + | Any (IterSysVars (vq1, vf1)), Any (IterSysVars (vq2, vf2)) -> VarQuery.compare vq1 vq2 (* not comparing fs *) (* only argumentless queries should remain *) | _, _ -> Stdlib.compare (order a) (order b) end From 639e783a9c513049ee92f17234a5cdbffb3cdfad Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 20 Jan 2022 14:05:50 +0200 Subject: [PATCH 207/402] Fix Gobview with changed global invariant type --- gobview | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gobview b/gobview index 3acd89c9ec..3f4a3cdd56 160000 --- a/gobview +++ b/gobview @@ -1 +1 @@ -Subproject commit 3acd89c9ec9b0714433ae3b9aa82d596a5c34aac +Subproject commit 3f4a3cdd56c9f4d2c5548d15eac3bb58b670dd1a From 8eeb2190a95207a941e1343570376b2d617aaf17 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 20 Jan 2022 14:22:33 +0200 Subject: [PATCH 208/402] Fix HTML view with FromSpec contexts --- g2html | 2 +- src/framework/analyses.ml | 12 +++++++++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/g2html b/g2html index 120a326f8e..49a7a8d21c 160000 --- a/g2html +++ b/g2html @@ -1 +1 @@ -Subproject commit 120a326f8ecadcc01fe601dc824decb8af2cf630 +Subproject commit 49a7a8d21c6741d57d35ee5ba175c8ff32a4d0b9 diff --git a/src/framework/analyses.ml b/src/framework/analyses.ml index a1db4a3bf1..87ec7f9fe0 100644 --- a/src/framework/analyses.ml +++ b/src/framework/analyses.ml @@ -84,7 +84,12 @@ module GVarG (G: Lattice.S) (C: Printable.S) = struct module CSet = struct - include SetDomain.Make (C) + include SetDomain.Make ( + struct + include C + let printXml f c = BatPrintf.fprintf f "%a" printXml c (* wrap in for HTML printing *) + end + ) let leq x y = !GU.postsolving || leq x y (* HACK: to pass verify*) end @@ -100,6 +105,11 @@ struct | _ -> failwith "GVarG.contexts" let create_spec spec = `Lifted1 spec let create_contexts contexts = `Lifted2 contexts + + let printXml f = function + | `Lifted1 x -> G.printXml f x + | `Lifted2 x -> BatPrintf.fprintf f "%a" CSet.printXml x + | x -> BatPrintf.fprintf f "%a" printXml x end From 0bd4893b17de4a9b042d923d7ee2ad697440c17e Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 20 Jan 2022 16:51:46 +0200 Subject: [PATCH 209/402] Move TD3 abort apron test to new apron2 group --- .github/workflows/locked.yml | 6 ++++-- .github/workflows/unlocked.yml | 18 ++++++++++++------ .../01-td3-self-abort-complex.c} | 0 3 files changed, 16 insertions(+), 8 deletions(-) rename tests/regression/{36-apron/98-td3-self-abort-complex.c => 45-apron2/01-td3-self-abort-complex.c} (100%) diff --git a/.github/workflows/locked.yml b/.github/workflows/locked.yml index 9cd8e922b6..9efafd782f 100644 --- a/.github/workflows/locked.yml +++ b/.github/workflows/locked.yml @@ -41,10 +41,12 @@ jobs: run: ./make.sh headers testci - name: Test apron regression # skipped by default but CI has apron, so explicitly test group (which ignores skipping -- it's now a feature!) - run: ruby scripts/update_suite.rb group apron -s; + run: | + ruby scripts/update_suite.rb group apron -s + ruby scripts/update_suite.rb group apron2 -s - name: Test apron octagon regression # skipped by default but CI has apron, so explicitly test group (which ignores skipping -- it's now a feature!) - run: ruby scripts/update_suite.rb group octagon -s + run: ruby scripts/update_suite.rb group octagon -s - name: Test apron regression (Mukherjee et. al SAS '17 paper') # skipped by default but CI has apron, so explicitly test group (which ignores skipping -- it's now a feature!) run: ruby scripts/update_suite.rb group apron-mukherjee -s diff --git a/.github/workflows/unlocked.yml b/.github/workflows/unlocked.yml index 55cf510442..4d858388eb 100644 --- a/.github/workflows/unlocked.yml +++ b/.github/workflows/unlocked.yml @@ -57,11 +57,13 @@ jobs: - name: Test apron regression # skipped by default but CI has apron, so explicitly test group (which ignores skipping -- it's now a feature!) if: ${{ matrix.apron }} - run: ruby scripts/update_suite.rb group apron -s + run: | + ruby scripts/update_suite.rb group apron -s + ruby scripts/update_suite.rb group apron2 -s - name: Test apron octagon regression # skipped by default but CI has apron, so explicitly test group (which ignores skipping -- it's now a feature!) if: ${{ matrix.apron }} - run: ruby scripts/update_suite.rb group octagon -s + run: ruby scripts/update_suite.rb group octagon -s - name: Test apron regression (Mukherjee et. al SAS '17 paper') # skipped by default but CI has apron, so explicitly test group (which ignores skipping -- it's now a feature!) if: ${{ matrix.apron }} @@ -138,10 +140,12 @@ jobs: - name: Test apron regression # skipped by default but CI has apron, so explicitly test group (which ignores skipping -- it's now a feature!) # if: ${{ matrix.apron }} - run: ruby scripts/update_suite.rb group apron -s + run: | + ruby scripts/update_suite.rb group apron -s + ruby scripts/update_suite.rb group apron2 -s - name: Test apron octagon regression # skipped by default but CI has apron, so explicitly test group (which ignores skipping -- it's now a feature!) - run: ruby scripts/update_suite.rb group octagon -s + run: ruby scripts/update_suite.rb group octagon -s - name: Test apron regression (Mukherjee et. al SAS '17 paper') # skipped by default but CI has apron, so explicitly test group (which ignores skipping -- it's now a feature!) # if: ${{ matrix.apron }} @@ -237,10 +241,12 @@ jobs: - name: Test apron regression # skipped by default but CI has apron, so explicitly test group (which ignores skipping -- it's now a feature!) # if: ${{ matrix.apron }} - run: ruby scripts/update_suite.rb group apron -s + run: | + ruby scripts/update_suite.rb group apron -s + ruby scripts/update_suite.rb group apron2 -s - name: Test apron octagon regression # skipped by default but CI has apron, so explicitly test group (which ignores skipping -- it's now a feature!) - run: ruby scripts/update_suite.rb group octagon -s + run: ruby scripts/update_suite.rb group octagon -s - name: Test apron regression (Mukherjee et. al SAS '17 paper') # skipped by default but CI has apron, so explicitly test group (which ignores skipping -- it's now a feature!) # if: ${{ matrix.apron }} diff --git a/tests/regression/36-apron/98-td3-self-abort-complex.c b/tests/regression/45-apron2/01-td3-self-abort-complex.c similarity index 100% rename from tests/regression/36-apron/98-td3-self-abort-complex.c rename to tests/regression/45-apron2/01-td3-self-abort-complex.c From b6e997ca925701c9bd87f7becd61de7aa4ae12f1 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Fri, 21 Jan 2022 15:25:59 +0200 Subject: [PATCH 210/402] Fix iter_sys_vars comment in ApronPriv --- src/analyses/apron/apronPriv.apron.ml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/analyses/apron/apronPriv.apron.ml b/src/analyses/apron/apronPriv.apron.ml index a01d31b08b..78dfe6e99a 100644 --- a/src/analyses/apron/apronPriv.apron.ml +++ b/src/analyses/apron/apronPriv.apron.ml @@ -39,7 +39,7 @@ module type S = val thread_join: Q.ask -> (V.t -> G.t) -> Cil.exp -> apron_components_t -> apron_components_t val thread_return: Q.ask -> (V.t -> G.t) -> (V.t -> G.t -> unit) -> ThreadIdDomain.Thread.t -> apron_components_t -> apron_components_t - val iter_sys_vars: (V.t -> G.t) -> VarQuery.t -> V.t VarQuery.f -> unit (** [Queries.IterSysVars] for base. *) + val iter_sys_vars: (V.t -> G.t) -> VarQuery.t -> V.t VarQuery.f -> unit (** [Queries.IterSysVars] for apron. *) val init: unit -> unit val finalize: unit -> unit From 09cd5f7bec97ce68fd74e15113ec49d23663a2d9 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Fri, 21 Jan 2022 15:28:35 +0200 Subject: [PATCH 211/402] Extract iter_sys_vars to OldPrivBase in BasePriv --- src/analyses/basePriv.ml | 24 ++++++------------------ 1 file changed, 6 insertions(+), 18 deletions(-) diff --git a/src/analyses/basePriv.ml b/src/analyses/basePriv.ml index 10f4a2c0e7..6e9dc2a7dc 100644 --- a/src/analyses/basePriv.ml +++ b/src/analyses/basePriv.ml @@ -60,6 +60,7 @@ module OldPrivBase = struct include NoFinalize module D = Lattice.Unit + module V = VarinfoV let startstate () = () @@ -77,6 +78,11 @@ struct true | _ -> !GU.earlyglobs && not (ThreadFlag.is_multi ask) + + let iter_sys_vars getg vq vf = + match vq with + | VarQuery.Global g -> vf g + | _ -> () end (* Copy of ProtectionBasedOldPriv with is_private constantly false. *) @@ -84,7 +90,6 @@ module NonePriv: S = struct include OldPrivBase module G = BaseDomain.VD - module V = VarinfoV let init () = () @@ -125,11 +130,6 @@ struct in (* We fold over the local state, and side effect the globals *) CPA.fold side_var st.cpa st - - let iter_sys_vars getg vq vf = - match vq with - | VarQuery.Global g -> vf g - | _ -> () end (** Protection-Based Reading old implementation. @@ -141,7 +141,6 @@ struct include OldPrivBase module G = BaseDomain.VD - module V = VarinfoV let init () = if get_string "ana.osek.oil" = "" then ConfCheck.RequireMutexActivatedInit.init () @@ -190,11 +189,6 @@ struct in (* We fold over the local state, and side effect the globals *) CPA.fold side_var st.cpa st - - let iter_sys_vars getg vq vf = - match vq with - | VarQuery.Global g -> vf g - | _ -> () end module PerMutexPrivBase = @@ -419,7 +413,6 @@ struct module D = MustVars module G = BaseDomain.VD - module V = VarinfoV let init () = if get_string "ana.osek.oil" = "" then ConfCheck.RequireMutexActivatedInit.init () @@ -484,11 +477,6 @@ struct CPA.fold side_var st.cpa st let threadenter = old_threadenter - - let iter_sys_vars getg vq vf = - match vq with - | VarQuery.Global g -> vf g - | _ -> () end module type PerGlobalPrivParam = From 4b7df8bc30f0e5c8e65a3708c3642a9eebee8e45 Mon Sep 17 00:00:00 2001 From: Julian Erhard Date: Thu, 27 Jan 2022 09:51:58 +0100 Subject: [PATCH 212/402] Add option for restarting unknowns belonging to global variables selected by the user. Adds the option incremental.restart_globs.globs, where a user can provide a list of global variables which should be restarted. --- src/framework/analyses.ml | 9 +++++++-- src/incremental/compareCIL.ml | 3 ++- src/maingoblint.ml | 23 ++++++++++++++------- src/solvers/td3.ml | 38 +++++++++++++++++++++++++++++++++++ src/util/cilfacade.ml | 35 ++++++++++++++++++++++++++++++++ src/util/options.schema.json | 20 +++++++++++++++++- src/util/server.ml | 3 ++- 7 files changed, 119 insertions(+), 12 deletions(-) diff --git a/src/framework/analyses.ml b/src/framework/analyses.ml index eefb414596..10f4582e9a 100644 --- a/src/framework/analyses.ml +++ b/src/framework/analyses.ml @@ -452,13 +452,18 @@ type analyzed_data = { type increment_data = { old_data: analyzed_data option; new_file: Cil.file; - changes: CompareCIL.change_info + changes: CompareCIL.change_info; + + (* Globals for whiche the constraint + system unknowns should be restarted *) + restarting: Cil.global list; } let empty_increment_data file = { old_data = None; new_file = file; - changes = CompareCIL.empty_change_info () + changes = CompareCIL.empty_change_info (); + restarting = [] } (** A side-effecting system. *) diff --git a/src/incremental/compareCIL.ml b/src/incremental/compareCIL.ml index 2ce81948b7..470a941ff0 100644 --- a/src/incremental/compareCIL.ml +++ b/src/incremental/compareCIL.ml @@ -23,7 +23,8 @@ type change_info = { mutable added: global list } -let empty_change_info () : change_info = {added = []; removed = []; changed = []; unchanged = []} +let empty_change_info () : change_info = + {added = []; removed = []; changed = []; unchanged = []} (* If some CFGs of the two functions to be compared are provided, a fine-grained CFG comparison is done that also determines which * nodes of the function changed. If on the other hand no CFGs are provided, the "old" AST comparison on the CIL.file is diff --git a/src/maingoblint.ml b/src/maingoblint.ml index f2e8d685c3..7795703ff6 100644 --- a/src/maingoblint.ml +++ b/src/maingoblint.ml @@ -433,8 +433,8 @@ let check_arguments () = if get_bool "ana.base.context.int" && not (get_bool "ana.base.context.non-ptr") then (set_bool "ana.base.context.int" false; warn "ana.base.context.int implicitly disabled by ana.base.context.non-ptr"); (* order matters: non-ptr=false, int=true -> int=false cascades to interval=false with warning *) if get_bool "ana.base.context.interval" && not (get_bool "ana.base.context.int") then (set_bool "ana.base.context.interval" false; warn "ana.base.context.interval implicitly disabled by ana.base.context.int"); - if get_bool "incremental.only-rename" then (set_bool "incremental.load" true; warn "incremental.only-rename implicitly activates incremental.load. Previous AST is loaded for diff and rename, but analyis results are not reused.") - + if get_bool "incremental.only-rename" then (set_bool "incremental.load" true; warn "incremental.only-rename implicitly activates incremental.load. Previous AST is loaded for diff and rename, but analyis results are not reused."); + if get_bool "incremental.restart.sided.enabled" && get_string_list "incremental.restart_globs.globs" <> [] then (warn "Passing a non-empty list to incremental.restart_globs.globs (manual restarting) while incremental.restart.sided.enabled (automatic restarting) is activated. Aborting."; exit 5 ) let handle_extraspecials () = let funs = get_string_list "exp.extraspecials" in LibraryFunctions.add_lib_funs funs @@ -447,15 +447,20 @@ let diff_and_rename current_file = let warn m = eprint_color ("{yellow}Warning: "^m) in warn "incremental.load is activated but no data exists that can be loaded." end; - let (changes, old_file, version_map, max_ids) = + let (changes, restarting, old_file, version_map, max_ids) = if Serialize.results_exist () && GobConfig.get_bool "incremental.load" then begin let old_file = Serialize.load_data Serialize.CilFile in let (version_map, changes, max_ids) = VersionLookup.load_and_update_map old_file current_file in let max_ids = UpdateCil.update_ids old_file max_ids current_file version_map changes in - (changes, Some old_file, version_map, max_ids) + print_endline "trying to get the string list"; + let restarting = GobConfig.get_string_list "incremental.restart_globs.globs" in + print_endline "retrieved list of options!"; + (* TODO: Check whether passing current_file is correct, or whether we need the version map. *) + let restarting = BatList.filter_map (Cilfacade.global_from_name current_file) restarting in + (changes, restarting, Some old_file, version_map, max_ids) end else begin let (version_map, max_ids) = VersionLookup.create_map current_file in - (CompareCIL.empty_change_info (), None, version_map, max_ids) + (CompareCIL.empty_change_info (), [], None, version_map, max_ids) end in let solver_data = if Serialize.results_exist () && GobConfig.get_bool "incremental.load" && not (GobConfig.get_bool "incremental.only-rename") @@ -470,7 +475,7 @@ let diff_and_rename current_file = | Some cil_file, Some solver_data -> Some ({cil_file; solver_data}: Analyses.analyzed_data) | _, _ -> None in - {Analyses.changes = changes; old_data; new_file = current_file} + {Analyses.changes = changes; restarting; old_data; new_file = current_file} in change_info let () = (* signal for printing backtrace; other signals in Generic.SolverStats and Timeout *) @@ -503,7 +508,11 @@ let main () = ) in if get_bool "server.enabled" then Server.start file do_analyze else ( - let changeInfo = if GobConfig.get_bool "incremental.load" || GobConfig.get_bool "incremental.save" then diff_and_rename file else Analyses.empty_increment_data file in + let changeInfo = + if GobConfig.get_bool "incremental.load" || GobConfig.get_bool "incremental.save" then + diff_and_rename file + else + Analyses.empty_increment_data file in file|> do_analyze changeInfo; do_stats (); do_html_output (); diff --git a/src/solvers/td3.ml b/src/solvers/td3.ml index 77636ab07c..e637ecd9c1 100644 --- a/src/solvers/td3.ml +++ b/src/solvers/td3.ml @@ -719,6 +719,44 @@ module WP = ) marked_for_deletion ); + (* [destabilize_leaf] is meant for restarting of globals selected by the user. *) + (* Must be called on a leaf! *) + let destabilize_leaf (x : S.v) = + let destab_side_dep (x : S.v) = + match HM.find_option side_dep x with + | Some w -> + HM.remove side_dep x; + VS.iter (fun y -> + HM.remove stable y; + destabilize y; + ) w; + | None -> + ignore @@ Pretty.printf + "Could not find globals in side_dep, so side_dep %a is not restarted.\n" + S.Var.pretty_trace x + in + destab_side_dep x; + destabilize x; + restart_leaf x + in + let globals_to_restart = S.increment.restarting in + let get x = try HM.find rho x with Not_found -> S.Dom.bot () in + List.iter + (fun g -> + (* All gs arriving here should yield Some varinfo. *) + let g = Option.get @@ Cilfacade.varinfo_from_global g in + ignore @@ Pretty.printf "Restarting global %s.\n" g.vname; + S.iter_vars + get + (Global g) + (fun v -> + if HM.mem stable v then begin + destabilize_leaf v; + end + ) + ) + globals_to_restart; + let restart_and_destabilize x = (* destabilize_with_side doesn't restart x itself *) restart_leaf x; destabilize x diff --git a/src/util/cilfacade.ml b/src/util/cilfacade.ml index 1742ac86ff..f138fb5f25 100644 --- a/src/util/cilfacade.ml +++ b/src/util/cilfacade.ml @@ -21,6 +21,41 @@ let rec get_labelsLoc = function else loc +module String = struct + include String + let hash = Hashtbl.hash +end + +module SM = Hashtbl.Make(String) +let varinfo_map: Cil.global SM.t option ref = ref None + +let varinfo_from_global (g : Cil.global) : Cil.varinfo option = match g with + | GFun (f, _) -> Some f.svar + | GVar (v, _, _) -> Some v + | GVarDecl (v, _) -> Some v + | _ -> + Messages.warn + ~category:MessageCategory.Analyzer + "Not considering global cil object %a for restarting." + Cil.d_global g; + None + +let init_hash_map (file: Cil.file): Cil.global SM.t = + let vm = SM.create 113 in + varinfo_map := Some vm; + Cil.iterGlobals file + (fun v -> + match varinfo_from_global v with + | Some vi -> SM.add vm vi.vname v + | None -> ()); + vm + +let global_from_name (file: Cil.file) (name: string) = + let vm = (match !varinfo_map with + | None -> init_hash_map file + | Some vm -> vm) in + SM.find_opt vm name + let get_stmtkindLoc = Cil.get_stmtLoc (* CIL has a confusing name for this function *) let get_stmtLoc stmt = diff --git a/src/util/options.schema.json b/src/util/options.schema.json index 070daf4cce..2d57ead24c 100644 --- a/src/util/options.schema.json +++ b/src/util/options.schema.json @@ -902,7 +902,25 @@ "description": "List of functions that are to be re-analayzed from scratch", "type": "array", - "items": { "type": "string" }, + "items": { + "type": "string" + }, + "default": [] + } + }, + "additionalProperties": false + }, + "restart_globs": { + "title": "incremental.restart_globs", + "type": "object", + "properties": { + "globs": { + "title": "incremental.restart_globs.globs", + "description": "List of globals for which the analysis is to be restarted.", + "type": "array", + "items": { + "type": "string" + }, "default": [] } }, diff --git a/src/util/server.ml b/src/util/server.ml index a47e6a1a02..6ea9af6979 100644 --- a/src/util/server.ml +++ b/src/util/server.ml @@ -113,7 +113,8 @@ let analyze ?(reset=false) ({ file; do_analyze; _ }: t)= | Some solver_data -> let changes = CompareCIL.compareCilFiles file file in let old_data = Some { Analyses.cil_file = file; solver_data } in - { Analyses.changes; old_data; new_file = file }, false + (* TODO: get globals for restarting from config *) + { Analyses.changes; old_data; new_file = file; restarting = [] }, false | _ -> Analyses.empty_increment_data file, true in GobConfig.set_bool "incremental.load" (not fresh); From b7d195e7f87bb46b25ee486cf18e88014f2b8b3c Mon Sep 17 00:00:00 2001 From: Julian Erhard Date: Thu, 27 Jan 2022 10:12:57 +0100 Subject: [PATCH 213/402] Add test for manual restarting --- .../01-restart_manual_simple.c | 9 ++++++ .../01-restart_manual_simple.json | 15 +++++++++ .../01-restart_manual_simple.patch | 31 +++++++++++++++++++ 3 files changed, 55 insertions(+) create mode 100644 tests/incremental/04-manual-restart/01-restart_manual_simple.c create mode 100644 tests/incremental/04-manual-restart/01-restart_manual_simple.json create mode 100644 tests/incremental/04-manual-restart/01-restart_manual_simple.patch diff --git a/tests/incremental/04-manual-restart/01-restart_manual_simple.c b/tests/incremental/04-manual-restart/01-restart_manual_simple.c new file mode 100644 index 0000000000..cbfb0ba70c --- /dev/null +++ b/tests/incremental/04-manual-restart/01-restart_manual_simple.c @@ -0,0 +1,9 @@ +#include + +int g = 4; + +int main() { + int x = g; + assert(x == 4); + return 0; +} diff --git a/tests/incremental/04-manual-restart/01-restart_manual_simple.json b/tests/incremental/04-manual-restart/01-restart_manual_simple.json new file mode 100644 index 0000000000..582ede8df1 --- /dev/null +++ b/tests/incremental/04-manual-restart/01-restart_manual_simple.json @@ -0,0 +1,15 @@ +{ + "exp": { + "earlyglobs": true + }, + "incremental": { + "restart": { + "sided": { + "enabled": false + } + }, + "restart_globs": { + "globs": [] + } + } +} diff --git a/tests/incremental/04-manual-restart/01-restart_manual_simple.patch b/tests/incremental/04-manual-restart/01-restart_manual_simple.patch new file mode 100644 index 0000000000..483ebe1bc1 --- /dev/null +++ b/tests/incremental/04-manual-restart/01-restart_manual_simple.patch @@ -0,0 +1,31 @@ +diff --git tests/incremental/04-manual-restart/01-restart_manual_simple.c tests/incremental/04-manual-restart/01-restart_manual_simple.c +index cbfb0ba70..aa83393ac 100644 +--- tests/incremental/04-manual-restart/01-restart_manual_simple.c ++++ tests/incremental/04-manual-restart/01-restart_manual_simple.c +@@ -1,9 +1,9 @@ + #include + +-int g = 4; ++int g = 5; + + int main() { + int x = g; +- assert(x == 4); ++ assert(x == 4); //FAIL + return 0; + } +diff --git tests/incremental/04-manual-restart/01-restart_manual_simple.json tests/incremental/04-manual-restart/01-restart_manual_simple.json +index 582ede8df..51d6d31b2 100644 +--- tests/incremental/04-manual-restart/01-restart_manual_simple.json ++++ tests/incremental/04-manual-restart/01-restart_manual_simple.json +@@ -9,7 +9,9 @@ + } + }, + "restart_globs": { +- "globs": [] ++ "globs": [ ++ "g" ++ ] + } + } + } From 37aefd6505224b8d6347369f222b70f7dec09934 Mon Sep 17 00:00:00 2001 From: Julian Erhard Date: Thu, 27 Jan 2022 10:40:34 +0100 Subject: [PATCH 214/402] Add test for manual restarting of globals when reads and writes occur in different functions --- .../04-manual-restart/02-read_write_global.c | 16 ++++++++++ .../02-read_write_global.json | 21 ++++++++++++ .../02-read_write_global.patch | 32 +++++++++++++++++++ 3 files changed, 69 insertions(+) create mode 100644 tests/incremental/04-manual-restart/02-read_write_global.c create mode 100644 tests/incremental/04-manual-restart/02-read_write_global.json create mode 100644 tests/incremental/04-manual-restart/02-read_write_global.patch diff --git a/tests/incremental/04-manual-restart/02-read_write_global.c b/tests/incremental/04-manual-restart/02-read_write_global.c new file mode 100644 index 0000000000..257aa969ac --- /dev/null +++ b/tests/incremental/04-manual-restart/02-read_write_global.c @@ -0,0 +1,16 @@ +int g = 0; + +void foo(){ + g = 1; +} + +void bar(){ + int x = g; + assert(x % 2 == 0); // UNKNOWN +} + +int main(){ + foo(); + bar(); + return 0; +} diff --git a/tests/incremental/04-manual-restart/02-read_write_global.json b/tests/incremental/04-manual-restart/02-read_write_global.json new file mode 100644 index 0000000000..8685ac3b70 --- /dev/null +++ b/tests/incremental/04-manual-restart/02-read_write_global.json @@ -0,0 +1,21 @@ +{ + "exp": { + "earlyglobs": true + }, + "ana": { + "int": { + "interval": true, + "congruence": true + } + }, + "incremental": { + "restart": { + "sided": { + "enabled": false + } + }, + "restart_globs": { + "globs": [] + } + } +} diff --git a/tests/incremental/04-manual-restart/02-read_write_global.patch b/tests/incremental/04-manual-restart/02-read_write_global.patch new file mode 100644 index 0000000000..92893d37c5 --- /dev/null +++ b/tests/incremental/04-manual-restart/02-read_write_global.patch @@ -0,0 +1,32 @@ +diff --git tests/incremental/04-manual-restart/02-read_write_global.c tests/incremental/04-manual-restart/02-read_write_global.c +index 257aa969a..521322dd0 100644 +--- tests/incremental/04-manual-restart/02-read_write_global.c ++++ tests/incremental/04-manual-restart/02-read_write_global.c +@@ -1,12 +1,12 @@ + int g = 0; + + void foo(){ +- g = 1; ++ g = 2; + } + + void bar(){ + int x = g; +- assert(x % 2 == 0); // UNKNOWN ++ assert(x % 2 == 0); + } + + int main(){ +diff --git tests/incremental/04-manual-restart/02-read_write_global.json tests/incremental/04-manual-restart/02-read_write_global.json +index 8685ac3b7..acf0568c8 100644 +--- tests/incremental/04-manual-restart/02-read_write_global.json ++++ tests/incremental/04-manual-restart/02-read_write_global.json +@@ -15,7 +15,7 @@ + } + }, + "restart_globs": { +- "globs": [] ++ "globs": ["g"] + } + } + } From 1e20f209bbac26d0bb4b425c066642021f97990b Mon Sep 17 00:00:00 2001 From: Julian Erhard Date: Thu, 27 Jan 2022 11:11:52 +0100 Subject: [PATCH 215/402] Change global_from_name to globals_from_names working on a list, remove usage of a mutable hashtable --- src/maingoblint.ml | 2 +- src/util/cilfacade.ml | 41 ++++++++++++++++------------------------- 2 files changed, 17 insertions(+), 26 deletions(-) diff --git a/src/maingoblint.ml b/src/maingoblint.ml index 7795703ff6..1a5e4159c4 100644 --- a/src/maingoblint.ml +++ b/src/maingoblint.ml @@ -456,7 +456,7 @@ let diff_and_rename current_file = let restarting = GobConfig.get_string_list "incremental.restart_globs.globs" in print_endline "retrieved list of options!"; (* TODO: Check whether passing current_file is correct, or whether we need the version map. *) - let restarting = BatList.filter_map (Cilfacade.global_from_name current_file) restarting in + let restarting = Cilfacade.globals_from_names current_file restarting in (changes, restarting, Some old_file, version_map, max_ids) end else begin let (version_map, max_ids) = VersionLookup.create_map current_file in diff --git a/src/util/cilfacade.ml b/src/util/cilfacade.ml index f138fb5f25..af2ea23ab8 100644 --- a/src/util/cilfacade.ml +++ b/src/util/cilfacade.ml @@ -26,35 +26,26 @@ module String = struct let hash = Hashtbl.hash end -module SM = Hashtbl.Make(String) -let varinfo_map: Cil.global SM.t option ref = ref None - let varinfo_from_global (g : Cil.global) : Cil.varinfo option = match g with | GFun (f, _) -> Some f.svar | GVar (v, _, _) -> Some v | GVarDecl (v, _) -> Some v - | _ -> - Messages.warn - ~category:MessageCategory.Analyzer - "Not considering global cil object %a for restarting." - Cil.d_global g; - None - -let init_hash_map (file: Cil.file): Cil.global SM.t = - let vm = SM.create 113 in - varinfo_map := Some vm; - Cil.iterGlobals file - (fun v -> - match varinfo_from_global v with - | Some vi -> SM.add vm vi.vname v - | None -> ()); - vm - -let global_from_name (file: Cil.file) (name: string) = - let vm = (match !varinfo_map with - | None -> init_hash_map file - | Some vm -> vm) in - SM.find_opt vm name + | _ -> None + +let globals_from_names (file: Cil.file) (names: string list): global list = + let module SM = Set.Make(String) in + let set = SM.of_list names in + let globals = + Cil.foldGlobals file (fun acc g -> + match varinfo_from_global g with + | Some v -> + if SM.mem v.vname set then + g::acc + else + acc + | None -> acc + ) [] in + globals let get_stmtkindLoc = Cil.get_stmtLoc (* CIL has a confusing name for this function *) From c5015757ed781c5b0300b6535979178fb4372cc9 Mon Sep 17 00:00:00 2001 From: Julian Erhard Date: Thu, 27 Jan 2022 11:35:31 +0100 Subject: [PATCH 216/402] Issue warning if both automatic and manual restarting are active instead of aborting --- src/maingoblint.ml | 3 ++- src/solvers/td3.ml | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/maingoblint.ml b/src/maingoblint.ml index 1a5e4159c4..28606da239 100644 --- a/src/maingoblint.ml +++ b/src/maingoblint.ml @@ -434,7 +434,8 @@ let check_arguments () = (* order matters: non-ptr=false, int=true -> int=false cascades to interval=false with warning *) if get_bool "ana.base.context.interval" && not (get_bool "ana.base.context.int") then (set_bool "ana.base.context.interval" false; warn "ana.base.context.interval implicitly disabled by ana.base.context.int"); if get_bool "incremental.only-rename" then (set_bool "incremental.load" true; warn "incremental.only-rename implicitly activates incremental.load. Previous AST is loaded for diff and rename, but analyis results are not reused."); - if get_bool "incremental.restart.sided.enabled" && get_string_list "incremental.restart_globs.globs" <> [] then (warn "Passing a non-empty list to incremental.restart_globs.globs (manual restarting) while incremental.restart.sided.enabled (automatic restarting) is activated. Aborting."; exit 5 ) + if get_bool "incremental.restart.sided.enabled" && get_string_list "incremental.restart_globs.globs" <> [] then warn "Passing a non-empty list to incremental.restart_globs.globs (manual restarting) while incremental.restart.sided.enabled (automatic restarting) is activated." + let handle_extraspecials () = let funs = get_string_list "exp.extraspecials" in LibraryFunctions.add_lib_funs funs diff --git a/src/solvers/td3.ml b/src/solvers/td3.ml index e637ecd9c1..73ceb2cd45 100644 --- a/src/solvers/td3.ml +++ b/src/solvers/td3.ml @@ -736,7 +736,7 @@ module WP = S.Var.pretty_trace x in destab_side_dep x; - destabilize x; + destabilize_normal x; restart_leaf x in let globals_to_restart = S.increment.restarting in From f9d01242de7d6888e732b7b0e4900b79ad79ca57 Mon Sep 17 00:00:00 2001 From: Julian Erhard Date: Thu, 27 Jan 2022 11:38:53 +0100 Subject: [PATCH 217/402] Remove unnecessary debug printout Co-authored-by: Simmo Saan --- src/maingoblint.ml | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/maingoblint.ml b/src/maingoblint.ml index 28606da239..7cd01b74cf 100644 --- a/src/maingoblint.ml +++ b/src/maingoblint.ml @@ -453,9 +453,7 @@ let diff_and_rename current_file = let old_file = Serialize.load_data Serialize.CilFile in let (version_map, changes, max_ids) = VersionLookup.load_and_update_map old_file current_file in let max_ids = UpdateCil.update_ids old_file max_ids current_file version_map changes in - print_endline "trying to get the string list"; let restarting = GobConfig.get_string_list "incremental.restart_globs.globs" in - print_endline "retrieved list of options!"; (* TODO: Check whether passing current_file is correct, or whether we need the version map. *) let restarting = Cilfacade.globals_from_names current_file restarting in (changes, restarting, Some old_file, version_map, max_ids) From 253a44c90254e65e65c565cbde27ab1e459e86eb Mon Sep 17 00:00:00 2001 From: Julian Erhard Date: Thu, 27 Jan 2022 13:34:52 +0100 Subject: [PATCH 218/402] Add logic for destabilize_front, handling superstable to destabilize_leaf. Copied and adapted code from destabilize_with_side --- src/solvers/td3.ml | 29 ++++++++++++++++++----------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/src/solvers/td3.ml b/src/solvers/td3.ml index 73ceb2cd45..c7788a8332 100644 --- a/src/solvers/td3.ml +++ b/src/solvers/td3.ml @@ -723,21 +723,28 @@ module WP = (* Must be called on a leaf! *) let destabilize_leaf (x : S.v) = let destab_side_dep (x : S.v) = - match HM.find_option side_dep x with - | Some w -> + let w = HM.find_default side_dep x VS.empty in + if not (VS.is_empty w) then ( HM.remove side_dep x; + (* add side_dep to front to prevent them from being aborted *) + destabilize_front ~front:true x w; + (* destabilize side dep to redo side effects *) VS.iter (fun y -> + if tracing then trace "sol2" "destabilize_leaf %a side_dep %a\n" S.Var.pretty_trace x S.Var.pretty_trace y; + if tracing then trace "sol2" "stable remove %a\n" S.Var.pretty_trace y; HM.remove stable y; - destabilize y; - ) w; - | None -> - ignore @@ Pretty.printf - "Could not find globals in side_dep, so side_dep %a is not restarted.\n" - S.Var.pretty_trace x + HM.remove superstable y; + destabilize y + ) w + ) in - destab_side_dep x; - destabilize_normal x; - restart_leaf x + if Node.equal (S.Var.node x) (Function Cil.dummyFunDec) then ( + restart_leaf x; + destab_side_dep x; + destabilize_normal x + ) else ( + ignore @@ Pretty.printf "Trying to restart %a which does not describe a global variable." S.Var.pretty_trace x + ) in let globals_to_restart = S.increment.restarting in let get x = try HM.find rho x with Not_found -> S.Dom.bot () in From 7fcc4b26211630d2b1af724e64ec05a2b999daf9 Mon Sep 17 00:00:00 2001 From: Julian Erhard Date: Thu, 27 Jan 2022 13:36:13 +0100 Subject: [PATCH 219/402] Reformat code for user-triggered global restarting --- src/solvers/td3.ml | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/src/solvers/td3.ml b/src/solvers/td3.ml index c7788a8332..e555732012 100644 --- a/src/solvers/td3.ml +++ b/src/solvers/td3.ml @@ -750,17 +750,16 @@ module WP = let get x = try HM.find rho x with Not_found -> S.Dom.bot () in List.iter (fun g -> - (* All gs arriving here should yield Some varinfo. *) - let g = Option.get @@ Cilfacade.varinfo_from_global g in - ignore @@ Pretty.printf "Restarting global %s.\n" g.vname; - S.iter_vars - get - (Global g) - (fun v -> - if HM.mem stable v then begin - destabilize_leaf v; - end - ) + (* All gs arriving here should yield Some varinfo. *) + let g = Option.get @@ Cilfacade.varinfo_from_global g in + S.iter_vars + get + (Global g) + (fun v -> + if HM.mem stable v then begin + destabilize_leaf v; + end + ) ) globals_to_restart; From 83dab6469277f77bddbfb4d5b3072f9b53b7b67c Mon Sep 17 00:00:00 2001 From: Julian Erhard Date: Thu, 27 Jan 2022 14:24:27 +0100 Subject: [PATCH 220/402] Collect varinfos instead of Cil.globals for manually restarted globals --- src/framework/analyses.ml | 2 +- src/maingoblint.ml | 3 +-- src/solvers/td3.ml | 6 +----- src/util/cilfacade.ml | 8 +++++--- 4 files changed, 8 insertions(+), 11 deletions(-) diff --git a/src/framework/analyses.ml b/src/framework/analyses.ml index 10f4582e9a..d1eb1e1f46 100644 --- a/src/framework/analyses.ml +++ b/src/framework/analyses.ml @@ -456,7 +456,7 @@ type increment_data = { (* Globals for whiche the constraint system unknowns should be restarted *) - restarting: Cil.global list; + restarting: Cil.varinfo list; } let empty_increment_data file = { diff --git a/src/maingoblint.ml b/src/maingoblint.ml index 7cd01b74cf..9ece899a60 100644 --- a/src/maingoblint.ml +++ b/src/maingoblint.ml @@ -454,8 +454,7 @@ let diff_and_rename current_file = let (version_map, changes, max_ids) = VersionLookup.load_and_update_map old_file current_file in let max_ids = UpdateCil.update_ids old_file max_ids current_file version_map changes in let restarting = GobConfig.get_string_list "incremental.restart_globs.globs" in - (* TODO: Check whether passing current_file is correct, or whether we need the version map. *) - let restarting = Cilfacade.globals_from_names current_file restarting in + let restarting = Cilfacade.global_varinfos_from_names current_file restarting in (changes, restarting, Some old_file, version_map, max_ids) end else begin let (version_map, max_ids) = VersionLookup.create_map current_file in diff --git a/src/solvers/td3.ml b/src/solvers/td3.ml index e555732012..d73f5f7e8e 100644 --- a/src/solvers/td3.ml +++ b/src/solvers/td3.ml @@ -750,11 +750,7 @@ module WP = let get x = try HM.find rho x with Not_found -> S.Dom.bot () in List.iter (fun g -> - (* All gs arriving here should yield Some varinfo. *) - let g = Option.get @@ Cilfacade.varinfo_from_global g in - S.iter_vars - get - (Global g) + S.iter_vars get (Global g) (fun v -> if HM.mem stable v then begin destabilize_leaf v; diff --git a/src/util/cilfacade.ml b/src/util/cilfacade.ml index af2ea23ab8..b115905398 100644 --- a/src/util/cilfacade.ml +++ b/src/util/cilfacade.ml @@ -32,15 +32,17 @@ let varinfo_from_global (g : Cil.global) : Cil.varinfo option = match g with | GVarDecl (v, _) -> Some v | _ -> None -let globals_from_names (file: Cil.file) (names: string list): global list = +(** Takes a [Cil.file] and a list of names of globals, and returns a + list of [varinfo]s of globals whose [vname] is contained in the argument list. *) +let global_varinfos_from_names (file: Cil.file) (names: string list): varinfo list = let module SM = Set.Make(String) in let set = SM.of_list names in let globals = Cil.foldGlobals file (fun acc g -> - match varinfo_from_global g with + match varinfo_from_global g with | Some v -> if SM.mem v.vname set then - g::acc + v::acc else acc | None -> acc From 2e6f19400a3182fbfa6cf4afddd79da02c81661f Mon Sep 17 00:00:00 2001 From: Julian Erhard Date: Thu, 27 Jan 2022 14:57:10 +0100 Subject: [PATCH 221/402] Reuse Printable.String instead of creating a new module for it --- src/util/cilfacade.ml | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/util/cilfacade.ml b/src/util/cilfacade.ml index b115905398..24bb996a9c 100644 --- a/src/util/cilfacade.ml +++ b/src/util/cilfacade.ml @@ -21,11 +21,6 @@ let rec get_labelsLoc = function else loc -module String = struct - include String - let hash = Hashtbl.hash -end - let varinfo_from_global (g : Cil.global) : Cil.varinfo option = match g with | GFun (f, _) -> Some f.svar | GVar (v, _, _) -> Some v @@ -35,7 +30,7 @@ let varinfo_from_global (g : Cil.global) : Cil.varinfo option = match g with (** Takes a [Cil.file] and a list of names of globals, and returns a list of [varinfo]s of globals whose [vname] is contained in the argument list. *) let global_varinfos_from_names (file: Cil.file) (names: string list): varinfo list = - let module SM = Set.Make(String) in + let module SM = Set.Make(Printable.Strings) in let set = SM.of_list names in let globals = Cil.foldGlobals file (fun acc g -> From dd8cf517550f578bb8f17a6c4b80b4bddf383be7 Mon Sep 17 00:00:00 2001 From: Julian Erhard Date: Thu, 27 Jan 2022 15:16:39 +0100 Subject: [PATCH 222/402] Annotate that earlyglobs is reason for imprecision --- .../04-manual-restart/02-read_write_global.c | 2 +- .../04-manual-restart/02-read_write_global.patch | 12 +++++++----- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/tests/incremental/04-manual-restart/02-read_write_global.c b/tests/incremental/04-manual-restart/02-read_write_global.c index 257aa969ac..8a93caabe3 100644 --- a/tests/incremental/04-manual-restart/02-read_write_global.c +++ b/tests/incremental/04-manual-restart/02-read_write_global.c @@ -6,7 +6,7 @@ void foo(){ void bar(){ int x = g; - assert(x % 2 == 0); // UNKNOWN + assert(x % 2 == 0); // UNKNOWN (imprecision caused by earlyglobs) } int main(){ diff --git a/tests/incremental/04-manual-restart/02-read_write_global.patch b/tests/incremental/04-manual-restart/02-read_write_global.patch index 92893d37c5..1563f54146 100644 --- a/tests/incremental/04-manual-restart/02-read_write_global.patch +++ b/tests/incremental/04-manual-restart/02-read_write_global.patch @@ -1,5 +1,5 @@ diff --git tests/incremental/04-manual-restart/02-read_write_global.c tests/incremental/04-manual-restart/02-read_write_global.c -index 257aa969a..521322dd0 100644 +index 8a93caabe..521322dd0 100644 --- tests/incremental/04-manual-restart/02-read_write_global.c +++ tests/incremental/04-manual-restart/02-read_write_global.c @@ -1,12 +1,12 @@ @@ -12,21 +12,23 @@ index 257aa969a..521322dd0 100644 void bar(){ int x = g; -- assert(x % 2 == 0); // UNKNOWN +- assert(x % 2 == 0); // UNKNOWN (imprecision caused by earlyglobs) + assert(x % 2 == 0); } int main(){ diff --git tests/incremental/04-manual-restart/02-read_write_global.json tests/incremental/04-manual-restart/02-read_write_global.json -index 8685ac3b7..acf0568c8 100644 +index 8685ac3b7..b0bb607d9 100644 --- tests/incremental/04-manual-restart/02-read_write_global.json +++ tests/incremental/04-manual-restart/02-read_write_global.json -@@ -15,7 +15,7 @@ +@@ -15,7 +15,9 @@ } }, "restart_globs": { - "globs": [] -+ "globs": ["g"] ++ "globs": [ ++ "g" ++ ] } } } From e7d591e4c1a0440d12645e691abf66918c95b8e1 Mon Sep 17 00:00:00 2001 From: Julian Erhard Date: Thu, 27 Jan 2022 15:17:50 +0100 Subject: [PATCH 223/402] Comment that check is a hack to determine whether unknown relates to a global variable --- src/solvers/td3.ml | 1 + 1 file changed, 1 insertion(+) diff --git a/src/solvers/td3.ml b/src/solvers/td3.ml index d73f5f7e8e..15fa931621 100644 --- a/src/solvers/td3.ml +++ b/src/solvers/td3.ml @@ -738,6 +738,7 @@ module WP = ) w ) in + (* Hack: Only restart unknowns describing global variables *) if Node.equal (S.Var.node x) (Function Cil.dummyFunDec) then ( restart_leaf x; destab_side_dep x; From f5ee0948bd2da46474a6c2b3ca1794ffbf06530b Mon Sep 17 00:00:00 2001 From: Julian Erhard Date: Fri, 28 Jan 2022 10:00:18 +0100 Subject: [PATCH 224/402] Allow manual restarting of functions --- src/framework/analyses.ml | 2 +- src/maingoblint.ml | 2 +- src/solvers/td3.ml | 21 +++++++------------ src/util/cilUtil.ml | 43 +++++++++++++++++++++++++++++++++++++++ src/util/cilfacade.ml | 23 --------------------- 5 files changed, 52 insertions(+), 39 deletions(-) create mode 100644 src/util/cilUtil.ml diff --git a/src/framework/analyses.ml b/src/framework/analyses.ml index d1eb1e1f46..6a1dc4c60b 100644 --- a/src/framework/analyses.ml +++ b/src/framework/analyses.ml @@ -456,7 +456,7 @@ type increment_data = { (* Globals for whiche the constraint system unknowns should be restarted *) - restarting: Cil.varinfo list; + restarting: VarQuery.t list; } let empty_increment_data file = { diff --git a/src/maingoblint.ml b/src/maingoblint.ml index 9ece899a60..3f07656683 100644 --- a/src/maingoblint.ml +++ b/src/maingoblint.ml @@ -454,7 +454,7 @@ let diff_and_rename current_file = let (version_map, changes, max_ids) = VersionLookup.load_and_update_map old_file current_file in let max_ids = UpdateCil.update_ids old_file max_ids current_file version_map changes in let restarting = GobConfig.get_string_list "incremental.restart_globs.globs" in - let restarting = Cilfacade.global_varinfos_from_names current_file restarting in + let restarting = CilUtil.varquery_from_names current_file restarting in (changes, restarting, Some old_file, version_map, max_ids) end else begin let (version_map, max_ids) = VersionLookup.create_map current_file in diff --git a/src/solvers/td3.ml b/src/solvers/td3.ml index 15fa931621..aed49ba145 100644 --- a/src/solvers/td3.ml +++ b/src/solvers/td3.ml @@ -738,25 +738,18 @@ module WP = ) w ) in - (* Hack: Only restart unknowns describing global variables *) - if Node.equal (S.Var.node x) (Function Cil.dummyFunDec) then ( - restart_leaf x; - destab_side_dep x; - destabilize_normal x - ) else ( - ignore @@ Pretty.printf "Trying to restart %a which does not describe a global variable." S.Var.pretty_trace x - ) + restart_leaf x; + destab_side_dep x; + destabilize_normal x + in let globals_to_restart = S.increment.restarting in let get x = try HM.find rho x with Not_found -> S.Dom.bot () in + List.iter (fun g -> - S.iter_vars get (Global g) - (fun v -> - if HM.mem stable v then begin - destabilize_leaf v; - end - ) + S.iter_vars get g + (fun v -> if HM.mem stable v then destabilize_leaf v) ) globals_to_restart; diff --git a/src/util/cilUtil.ml b/src/util/cilUtil.ml new file mode 100644 index 0000000000..9041bf12ec --- /dev/null +++ b/src/util/cilUtil.ml @@ -0,0 +1,43 @@ +(** Functionality to create [VarQuery.t] lists from a list of names of global variable and function definitions *) +(* Separate file from cilfacade.ml, for functions that depend both on [Node] and [VarQuery]. Avoids dependency cycle *) + +module type S = +sig + val varquery_from_names : Cil.file -> string list -> VarQuery.t list +end + +module M : S = +struct + let varinfo_from_global (g : Cil.global) : Cil.varinfo option = match g with + | GFun (f, _) -> Some f.svar + | GVar (v, _, _) -> Some v + | GVarDecl (v, _) -> Some v + | _ -> None + + let varquery_from_global (g : Cil.global) : VarQuery.t option = match g with + | GFun (f, _) -> Some (VarQuery.Node {node = FunctionEntry f; fundec = Some f}) + | GVar (v, _, _) -> Some (VarQuery.Global v) + | GVarDecl (v, _) -> Some (VarQuery.Global v) + | _ -> None + + (** Takes a [Cil.file] and a list of names of globals, and returns a + list of [VarQuery.t]s of globals whose [vname] is contained in the argument list. + For *) + let varquery_from_names (file: Cil.file) (names: string list): VarQuery.t list = + let module SM = Set.Make(Printable.Strings) in + let set = SM.of_list names in + let globals = + Cil.foldGlobals file (fun acc g -> + match varinfo_from_global g, varquery_from_global g with + | Some v, Some vq -> + begin match SM.mem v.vname set with + | true -> vq::acc + | _ -> acc + end + | None, None -> acc + | _, _ -> assert false + ) [] in + globals +end + +include M diff --git a/src/util/cilfacade.ml b/src/util/cilfacade.ml index 24bb996a9c..1742ac86ff 100644 --- a/src/util/cilfacade.ml +++ b/src/util/cilfacade.ml @@ -21,29 +21,6 @@ let rec get_labelsLoc = function else loc -let varinfo_from_global (g : Cil.global) : Cil.varinfo option = match g with - | GFun (f, _) -> Some f.svar - | GVar (v, _, _) -> Some v - | GVarDecl (v, _) -> Some v - | _ -> None - -(** Takes a [Cil.file] and a list of names of globals, and returns a - list of [varinfo]s of globals whose [vname] is contained in the argument list. *) -let global_varinfos_from_names (file: Cil.file) (names: string list): varinfo list = - let module SM = Set.Make(Printable.Strings) in - let set = SM.of_list names in - let globals = - Cil.foldGlobals file (fun acc g -> - match varinfo_from_global g with - | Some v -> - if SM.mem v.vname set then - v::acc - else - acc - | None -> acc - ) [] in - globals - let get_stmtkindLoc = Cil.get_stmtLoc (* CIL has a confusing name for this function *) let get_stmtLoc stmt = From 35896633ebfb8edf28c8d5dcada34d7fda6e4ddd Mon Sep 17 00:00:00 2001 From: Julian Erhard Date: Fri, 28 Jan 2022 11:27:48 +0100 Subject: [PATCH 225/402] Add test case for manual restarting of function with partial contexts --- .../04-manual-restart/03-partial_contexts.c | 11 ++++++++ .../03-partial_contexts.json | 19 ++++++++++++++ .../03-partial_contexts.patch | 26 +++++++++++++++++++ 3 files changed, 56 insertions(+) create mode 100644 tests/incremental/04-manual-restart/03-partial_contexts.c create mode 100644 tests/incremental/04-manual-restart/03-partial_contexts.json create mode 100644 tests/incremental/04-manual-restart/03-partial_contexts.patch diff --git a/tests/incremental/04-manual-restart/03-partial_contexts.c b/tests/incremental/04-manual-restart/03-partial_contexts.c new file mode 100644 index 0000000000..a2a7016734 --- /dev/null +++ b/tests/incremental/04-manual-restart/03-partial_contexts.c @@ -0,0 +1,11 @@ +#include +int foo(int x){ + return x; +} + +int main(){ + int x = 12; + int y = foo(x); + assert(x == y); + return 0; +} diff --git a/tests/incremental/04-manual-restart/03-partial_contexts.json b/tests/incremental/04-manual-restart/03-partial_contexts.json new file mode 100644 index 0000000000..99334fccb8 --- /dev/null +++ b/tests/incremental/04-manual-restart/03-partial_contexts.json @@ -0,0 +1,19 @@ +{ + "ana": { + "base": { + "context": { + "int": false + } + } + }, + "incremental": { + "restart": { + "sided": { + "enabled": false + } + }, + "restart_globs": { + "globs": [] + } + } +} diff --git a/tests/incremental/04-manual-restart/03-partial_contexts.patch b/tests/incremental/04-manual-restart/03-partial_contexts.patch new file mode 100644 index 0000000000..5245a4ac37 --- /dev/null +++ b/tests/incremental/04-manual-restart/03-partial_contexts.patch @@ -0,0 +1,26 @@ +diff --git tests/incremental/04-manual-restart/03-partial_contexts.c tests/incremental/04-manual-restart/03-partial_contexts.c +index a2a701673..d0b4d3efc 100644 +--- tests/incremental/04-manual-restart/03-partial_contexts.c ++++ tests/incremental/04-manual-restart/03-partial_contexts.c +@@ -4,7 +4,7 @@ int foo(int x){ + } + + int main(){ +- int x = 12; ++ int x = 13; + int y = foo(x); + assert(x == y); + return 0; +diff --git tests/incremental/04-manual-restart/03-partial_contexts.json tests/incremental/04-manual-restart/03-partial_contexts.json +index 99334fccb..3da6121a1 100644 +--- tests/incremental/04-manual-restart/03-partial_contexts.json ++++ tests/incremental/04-manual-restart/03-partial_contexts.json +@@ -13,7 +13,7 @@ + } + }, + "restart_globs": { +- "globs": [] ++ "globs": ["g"] + } + } + } From 1133721ced67cec241621931aecfd27e786f08b2 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Fri, 28 Jan 2022 12:49:05 +0200 Subject: [PATCH 226/402] Remove VarQuery example from TD3 --- src/solvers/td3.ml | 43 ------------------------------------------- 1 file changed, 43 deletions(-) diff --git a/src/solvers/td3.ml b/src/solvers/td3.ml index 77636ab07c..2a5ade6a64 100644 --- a/src/solvers/td3.ml +++ b/src/solvers/td3.ml @@ -960,49 +960,6 @@ module WP = print_data data "Data after postsolve"; - (* TODO: example debug output for queries, remove *) - Cil.iterGlobals !Cilfacade.current_file (function - | GVar (g, _, _) -> - ignore (Pretty.printf "%a:\n" CilType.Varinfo.pretty g); - let get x = try HM.find rho x with Not_found -> S.Dom.bot () in - S.iter_vars get (Global g) (fun v -> - let d = get v in - if not (S.Dom.is_bot d) then - ignore (Pretty.printf " %a: %a\n" S.Var.pretty_trace v S.Dom.pretty d) - ) - | GFun (fd, _) -> - ignore (Pretty.printf "%a:\n" CilType.Fundec.pretty fd); - ignore (Pretty.printf " entry:\n"); - let get x = try HM.find rho x with Not_found -> S.Dom.bot () in - let node: Node.t = FunctionEntry fd in - S.iter_vars get (Node {node; fundec=Some fd}) (fun v -> - let d = get v in - if not (S.Dom.is_bot d) then - ignore (Pretty.printf " %a: %a\n" S.Var.pretty_trace v S.Dom.pretty d) - ); - List.iter (fun stmt -> - ignore (Pretty.printf "%a:\n" CilType.Fundec.pretty fd); - ignore (Pretty.printf " %a:\n" Cilfacade.stmt_pretty_short stmt); - let get x = try HM.find rho x with Not_found -> S.Dom.bot () in - let node: Node.t = Statement stmt in - S.iter_vars get (Node {node; fundec=Some fd}) (fun v -> - let d = get v in - if not (S.Dom.is_bot d) then - ignore (Pretty.printf " %a: %a\n" S.Var.pretty_trace v S.Dom.pretty d) - ) - ) fd.sallstmts; - ignore (Pretty.printf "%a:\n" CilType.Fundec.pretty fd); - ignore (Pretty.printf " return:\n"); - let get x = try HM.find rho x with Not_found -> S.Dom.bot () in - let node: Node.t = Function fd in - S.iter_vars get (Node {node; fundec=Some fd}) (fun v -> - let d = get v in - if not (S.Dom.is_bot d) then - ignore (Pretty.printf " %a: %a\n" S.Var.pretty_trace v S.Dom.pretty d) - ) - | _ -> () - ); - {st; infl; sides; rho; wpoint; stable; side_dep; side_infl; var_messages} let solve box st vs = From 2e688a2ec1255f381fcfa93aba1a4725d8fffcf2 Mon Sep 17 00:00:00 2001 From: Julian Erhard Date: Fri, 28 Jan 2022 16:31:07 +0100 Subject: [PATCH 227/402] Fix json in diff so to restart function foo --- .../04-manual-restart/03-partial_contexts.patch | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/tests/incremental/04-manual-restart/03-partial_contexts.patch b/tests/incremental/04-manual-restart/03-partial_contexts.patch index 5245a4ac37..295e2a5fa9 100644 --- a/tests/incremental/04-manual-restart/03-partial_contexts.patch +++ b/tests/incremental/04-manual-restart/03-partial_contexts.patch @@ -12,15 +12,17 @@ index a2a701673..d0b4d3efc 100644 assert(x == y); return 0; diff --git tests/incremental/04-manual-restart/03-partial_contexts.json tests/incremental/04-manual-restart/03-partial_contexts.json -index 99334fccb..3da6121a1 100644 +index 99334fccb..42a1da505 100644 --- tests/incremental/04-manual-restart/03-partial_contexts.json +++ tests/incremental/04-manual-restart/03-partial_contexts.json -@@ -13,7 +13,7 @@ +@@ -13,7 +13,9 @@ } }, "restart_globs": { - "globs": [] -+ "globs": ["g"] ++ "globs": [ ++ "foo" ++ ] } } } From ebb9b602832e26fa248f7d6487024ee12a9b203b Mon Sep 17 00:00:00 2001 From: Julian Erhard Date: Fri, 28 Jan 2022 16:38:54 +0100 Subject: [PATCH 228/402] Change call to destabilize to destabilize_normal. Manual restarting should not cause transitively restarting other unknowns, even in case that restart.sided.enabled is true. The destabilize function relies on a reference to chose the function whose implementation is actually used and may use the destabilize_with_side internally. This is avoided by calling destabilze_normal. --- src/solvers/td3.ml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/solvers/td3.ml b/src/solvers/td3.ml index aed49ba145..ee5e7c29e3 100644 --- a/src/solvers/td3.ml +++ b/src/solvers/td3.ml @@ -734,7 +734,7 @@ module WP = if tracing then trace "sol2" "stable remove %a\n" S.Var.pretty_trace y; HM.remove stable y; HM.remove superstable y; - destabilize y + destabilize_normal y ) w ) in From 2f98aa00ac1e60c251b7be20569d6c5747c92518 Mon Sep 17 00:00:00 2001 From: Julian Erhard Date: Mon, 31 Jan 2022 14:49:24 +0100 Subject: [PATCH 229/402] Manual restarting: check whether unkown is a leaf, and warn if it is not. --- src/solvers/td3.ml | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/solvers/td3.ml b/src/solvers/td3.ml index ee5e7c29e3..06f5ccd5e4 100644 --- a/src/solvers/td3.ml +++ b/src/solvers/td3.ml @@ -748,8 +748,12 @@ module WP = List.iter (fun g -> - S.iter_vars get g - (fun v -> if HM.mem stable v then destabilize_leaf v) + S.iter_vars get g + (fun v -> + if S.system v <> None then + ignore @@ Pretty.printf "Trying to restart a non-leaf unknown. This has no effect." + else if HM.mem stable v then + destabilize_leaf v) ) globals_to_restart; From 293ba9e03963f8eb2bc4e8ec7fe86586823b41c9 Mon Sep 17 00:00:00 2001 From: Julian Erhard Date: Mon, 31 Jan 2022 14:52:32 +0100 Subject: [PATCH 230/402] Add pretty printing of unknown in printout. --- src/solvers/td3.ml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/solvers/td3.ml b/src/solvers/td3.ml index 06f5ccd5e4..c2beee72da 100644 --- a/src/solvers/td3.ml +++ b/src/solvers/td3.ml @@ -751,7 +751,7 @@ module WP = S.iter_vars get g (fun v -> if S.system v <> None then - ignore @@ Pretty.printf "Trying to restart a non-leaf unknown. This has no effect." + ignore @@ Pretty.printf "Trying to restart non-leaf unknown %a. This has no effect.\n" S.Var.pretty_trace v else if HM.mem stable v then destabilize_leaf v) ) From 6afc7838e0cb6fc764be1a6285569406cbde52d2 Mon Sep 17 00:00:00 2001 From: Julian Erhard Date: Mon, 31 Jan 2022 15:36:23 +0100 Subject: [PATCH 231/402] Manual global restarting: Warn about globals that should be restarted according to option, but cannot be found in the CIL-file. --- src/maingoblint.ml | 13 +++++++++++-- src/util/cilUtil.ml | 24 ++++++++++++++---------- 2 files changed, 25 insertions(+), 12 deletions(-) diff --git a/src/maingoblint.ml b/src/maingoblint.ml index 3f07656683..3177581278 100644 --- a/src/maingoblint.ml +++ b/src/maingoblint.ml @@ -444,8 +444,8 @@ let handle_extraspecials () = let diff_and_rename current_file = (* Create change info, either from old results, or from scratch if there are no previous results. *) let change_info: Analyses.increment_data = + let warn m = eprint_color ("{yellow}Warning: "^m) in if GobConfig.get_bool "incremental.load" && not (Serialize.results_exist ()) then begin - let warn m = eprint_color ("{yellow}Warning: "^m) in warn "incremental.load is activated but no data exists that can be loaded." end; let (changes, restarting, old_file, version_map, max_ids) = @@ -454,7 +454,16 @@ let diff_and_rename current_file = let (version_map, changes, max_ids) = VersionLookup.load_and_update_map old_file current_file in let max_ids = UpdateCil.update_ids old_file max_ids current_file version_map changes in let restarting = GobConfig.get_string_list "incremental.restart_globs.globs" in - let restarting = CilUtil.varquery_from_names current_file restarting in + + let restarting, not_found = CilUtil.varquery_from_names current_file restarting in + + if not (List.is_empty not_found) then begin + List.iter + (fun s -> + warn @@ "Should restart " ^ s ^ " but no such global could not be found in the CIL-file.") + not_found; + flush stderr + end; (changes, restarting, Some old_file, version_map, max_ids) end else begin let (version_map, max_ids) = VersionLookup.create_map current_file in diff --git a/src/util/cilUtil.ml b/src/util/cilUtil.ml index 9041bf12ec..095c76ad57 100644 --- a/src/util/cilUtil.ml +++ b/src/util/cilUtil.ml @@ -3,7 +3,7 @@ module type S = sig - val varquery_from_names : Cil.file -> string list -> VarQuery.t list + val varquery_from_names : Cil.file -> string list -> VarQuery.t list * string list end module M : S = @@ -20,24 +20,28 @@ struct | GVarDecl (v, _) -> Some (VarQuery.Global v) | _ -> None - (** Takes a [Cil.file] and a list of names of globals, and returns a - list of [VarQuery.t]s of globals whose [vname] is contained in the argument list. - For *) - let varquery_from_names (file: Cil.file) (names: string list): VarQuery.t list = + (** Takes a [Cil.file] and a list of names of globals.contents + Returns a list of [VarQuery.t]s of globals whose [vname] is contained in the argument list, + and the list of names for which no global with the name could be found. *) + let varquery_from_names (file: Cil.file) (names: string list): VarQuery.t list * string list = let module SM = Set.Make(Printable.Strings) in let set = SM.of_list names in - let globals = - Cil.foldGlobals file (fun acc g -> + + (* Find list of [Cil.global]s that have one of the queried names, and a set of the found names *) + let globals, matched = + Cil.foldGlobals file (fun ((globs, matched) as acc) g -> match varinfo_from_global g, varquery_from_global g with | Some v, Some vq -> begin match SM.mem v.vname set with - | true -> vq::acc + | true -> (vq::globs, SM.add v.vname matched) | _ -> acc end | None, None -> acc | _, _ -> assert false - ) [] in - globals + ) ([], SM.empty) in + (* List of queried but not found names *) + let unmatched = List.filter (fun s -> not @@ SM.mem s matched) names in + globals, unmatched end include M From 2a1665b842f9048b899f15aa242c72b491b078d5 Mon Sep 17 00:00:00 2001 From: Julian Erhard Date: Mon, 31 Jan 2022 15:51:08 +0100 Subject: [PATCH 232/402] Move contents from cilUtil to varQuery --- src/framework/varQuery.ml | 35 ++++++++++++++++++++++++++++ src/framework/varQuery.mli | 6 +++++ src/maingoblint.ml | 2 +- src/util/cilUtil.ml | 47 -------------------------------------- 4 files changed, 42 insertions(+), 48 deletions(-) create mode 100644 src/framework/varQuery.mli delete mode 100644 src/util/cilUtil.ml diff --git a/src/framework/varQuery.ml b/src/framework/varQuery.ml index d3c3a88a4f..39072d5322 100644 --- a/src/framework/varQuery.ml +++ b/src/framework/varQuery.ml @@ -4,3 +4,38 @@ type t = [@@deriving ord] type 'v f = 'v -> unit + +let varinfo_from_global (g : Cil.global) : Cil.varinfo option = match g with + | GFun (f, _) -> Some f.svar + | GVar (v, _, _) -> Some v + | GVarDecl (v, _) -> Some v + | _ -> None + +let varquery_from_global (g : Cil.global) : t option = match g with + | GFun (f, _) -> Some (Node {node = FunctionEntry f; fundec = Some f}) + | GVar (v, _, _) -> Some (Global v) + | GVarDecl (v, _) -> Some (Global v) + | _ -> None + +(** Takes a [Cil.file] and a list of names of globals.contents + Returns a list of [VarQuery.t]s of globals whose [vname] is contained in the argument list, + and the list of names for which no global with the name could be found. *) +let varqueries_from_names (file: Cil.file) (names: string list): t list * string list = + let module SM = Set.Make(Printable.Strings) in + let set = SM.of_list names in + + (* Find list of [Cil.global]s that have one of the queried names, and a set of the found names *) + let globals, matched = + Cil.foldGlobals file (fun ((globs, matched) as acc) g -> + match varinfo_from_global g, varquery_from_global g with + | Some v, Some vq -> + begin match SM.mem v.vname set with + | true -> (vq::globs, SM.add v.vname matched) + | _ -> acc + end + | None, None -> acc + | _, _ -> assert false + ) ([], SM.empty) in + (* List of queried but not found names *) + let unmatched = List.filter (fun s -> not @@ SM.mem s matched) names in + globals, unmatched diff --git a/src/framework/varQuery.mli b/src/framework/varQuery.mli new file mode 100644 index 0000000000..40a9ba31f0 --- /dev/null +++ b/src/framework/varQuery.mli @@ -0,0 +1,6 @@ +type t = + Global of Cil.varinfo + | Node of { node : Node.t; fundec : Cil.fundec option; } +val compare : t -> t -> int +type 'v f = 'v -> unit +val varqueries_from_names : Cil.file -> string list -> t list * string list diff --git a/src/maingoblint.ml b/src/maingoblint.ml index 3177581278..8945014087 100644 --- a/src/maingoblint.ml +++ b/src/maingoblint.ml @@ -455,7 +455,7 @@ let diff_and_rename current_file = let max_ids = UpdateCil.update_ids old_file max_ids current_file version_map changes in let restarting = GobConfig.get_string_list "incremental.restart_globs.globs" in - let restarting, not_found = CilUtil.varquery_from_names current_file restarting in + let restarting, not_found = VarQuery.varqueries_from_names current_file restarting in if not (List.is_empty not_found) then begin List.iter diff --git a/src/util/cilUtil.ml b/src/util/cilUtil.ml deleted file mode 100644 index 095c76ad57..0000000000 --- a/src/util/cilUtil.ml +++ /dev/null @@ -1,47 +0,0 @@ -(** Functionality to create [VarQuery.t] lists from a list of names of global variable and function definitions *) -(* Separate file from cilfacade.ml, for functions that depend both on [Node] and [VarQuery]. Avoids dependency cycle *) - -module type S = -sig - val varquery_from_names : Cil.file -> string list -> VarQuery.t list * string list -end - -module M : S = -struct - let varinfo_from_global (g : Cil.global) : Cil.varinfo option = match g with - | GFun (f, _) -> Some f.svar - | GVar (v, _, _) -> Some v - | GVarDecl (v, _) -> Some v - | _ -> None - - let varquery_from_global (g : Cil.global) : VarQuery.t option = match g with - | GFun (f, _) -> Some (VarQuery.Node {node = FunctionEntry f; fundec = Some f}) - | GVar (v, _, _) -> Some (VarQuery.Global v) - | GVarDecl (v, _) -> Some (VarQuery.Global v) - | _ -> None - - (** Takes a [Cil.file] and a list of names of globals.contents - Returns a list of [VarQuery.t]s of globals whose [vname] is contained in the argument list, - and the list of names for which no global with the name could be found. *) - let varquery_from_names (file: Cil.file) (names: string list): VarQuery.t list * string list = - let module SM = Set.Make(Printable.Strings) in - let set = SM.of_list names in - - (* Find list of [Cil.global]s that have one of the queried names, and a set of the found names *) - let globals, matched = - Cil.foldGlobals file (fun ((globs, matched) as acc) g -> - match varinfo_from_global g, varquery_from_global g with - | Some v, Some vq -> - begin match SM.mem v.vname set with - | true -> (vq::globs, SM.add v.vname matched) - | _ -> acc - end - | None, None -> acc - | _, _ -> assert false - ) ([], SM.empty) in - (* List of queried but not found names *) - let unmatched = List.filter (fun s -> not @@ SM.mem s matched) names in - globals, unmatched -end - -include M From 8268dc0e447f9cbe4800f673ed5fed97cdd9a6cf Mon Sep 17 00:00:00 2001 From: Julian Erhard Date: Tue, 1 Feb 2022 18:09:47 +0100 Subject: [PATCH 233/402] Move documentation comment to .mli file --- src/framework/varQuery.ml | 3 --- src/framework/varQuery.mli | 4 ++++ 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/framework/varQuery.ml b/src/framework/varQuery.ml index 39072d5322..40e856c900 100644 --- a/src/framework/varQuery.ml +++ b/src/framework/varQuery.ml @@ -17,9 +17,6 @@ let varquery_from_global (g : Cil.global) : t option = match g with | GVarDecl (v, _) -> Some (Global v) | _ -> None -(** Takes a [Cil.file] and a list of names of globals.contents - Returns a list of [VarQuery.t]s of globals whose [vname] is contained in the argument list, - and the list of names for which no global with the name could be found. *) let varqueries_from_names (file: Cil.file) (names: string list): t list * string list = let module SM = Set.Make(Printable.Strings) in let set = SM.of_list names in diff --git a/src/framework/varQuery.mli b/src/framework/varQuery.mli index 40a9ba31f0..01c7eda99f 100644 --- a/src/framework/varQuery.mli +++ b/src/framework/varQuery.mli @@ -3,4 +3,8 @@ type t = | Node of { node : Node.t; fundec : Cil.fundec option; } val compare : t -> t -> int type 'v f = 'v -> unit + +(** Takes a [Cil.file] and a list of names of globals.contents + Returns a list of [VarQuery.t]s of globals whose [vname] is contained in the argument list, + and the list of names for which no global with the name could be found. *) val varqueries_from_names : Cil.file -> string list -> t list * string list From ac4cb98ff18df5b92fa9614160e448c7c5a9b23f Mon Sep 17 00:00:00 2001 From: Julian Erhard Date: Fri, 11 Feb 2022 11:16:40 +0100 Subject: [PATCH 234/402] Rename option incremental.restart_globs.globs to incremental.restart.list --- src/maingoblint.ml | 4 +-- src/util/options.schema.json | 25 +++++++------------ .../01-restart_manual_simple.json | 6 ++--- .../01-restart_manual_simple.patch | 16 ++++++------ .../02-read_write_global.json | 6 ++--- .../02-read_write_global.patch | 14 +++++------ .../03-partial_contexts.json | 6 ++--- .../03-partial_contexts.patch | 14 +++++------ 8 files changed, 38 insertions(+), 53 deletions(-) diff --git a/src/maingoblint.ml b/src/maingoblint.ml index 8945014087..1eea6ff0ef 100644 --- a/src/maingoblint.ml +++ b/src/maingoblint.ml @@ -434,7 +434,7 @@ let check_arguments () = (* order matters: non-ptr=false, int=true -> int=false cascades to interval=false with warning *) if get_bool "ana.base.context.interval" && not (get_bool "ana.base.context.int") then (set_bool "ana.base.context.interval" false; warn "ana.base.context.interval implicitly disabled by ana.base.context.int"); if get_bool "incremental.only-rename" then (set_bool "incremental.load" true; warn "incremental.only-rename implicitly activates incremental.load. Previous AST is loaded for diff and rename, but analyis results are not reused."); - if get_bool "incremental.restart.sided.enabled" && get_string_list "incremental.restart_globs.globs" <> [] then warn "Passing a non-empty list to incremental.restart_globs.globs (manual restarting) while incremental.restart.sided.enabled (automatic restarting) is activated." + if get_bool "incremental.restart.sided.enabled" && get_string_list "incremental.restart.list" <> [] then warn "Passing a non-empty list to incremental.restart.list (manual restarting) while incremental.restart.sided.enabled (automatic restarting) is activated." let handle_extraspecials () = let funs = get_string_list "exp.extraspecials" in @@ -453,7 +453,7 @@ let diff_and_rename current_file = let old_file = Serialize.load_data Serialize.CilFile in let (version_map, changes, max_ids) = VersionLookup.load_and_update_map old_file current_file in let max_ids = UpdateCil.update_ids old_file max_ids current_file version_map changes in - let restarting = GobConfig.get_string_list "incremental.restart_globs.globs" in + let restarting = GobConfig.get_string_list "incremental.restart.list" in let restarting, not_found = VarQuery.varqueries_from_names current_file restarting in diff --git a/src/util/options.schema.json b/src/util/options.schema.json index 2d57ead24c..97fca8f05d 100644 --- a/src/util/options.schema.json +++ b/src/util/options.schema.json @@ -910,22 +910,6 @@ }, "additionalProperties": false }, - "restart_globs": { - "title": "incremental.restart_globs", - "type": "object", - "properties": { - "globs": { - "title": "incremental.restart_globs.globs", - "description": "List of globals for which the analysis is to be restarted.", - "type": "array", - "items": { - "type": "string" - }, - "default": [] - } - }, - "additionalProperties": false - }, "restart": { "title": "incremental.restart", "type": "object", @@ -948,6 +932,15 @@ } }, "additionalProperties": false + }, + "list": { + "title": "incremental.restart.list", + "description": "List of globals variables and function definitions for which the analysis is to be restarted.", + "type": "array", + "items": { + "type": "string" + }, + "default": [] } }, "additionalProperties": false diff --git a/tests/incremental/04-manual-restart/01-restart_manual_simple.json b/tests/incremental/04-manual-restart/01-restart_manual_simple.json index 582ede8df1..dbdb1d651e 100644 --- a/tests/incremental/04-manual-restart/01-restart_manual_simple.json +++ b/tests/incremental/04-manual-restart/01-restart_manual_simple.json @@ -6,10 +6,8 @@ "restart": { "sided": { "enabled": false - } - }, - "restart_globs": { - "globs": [] + }, + "list": [] } } } diff --git a/tests/incremental/04-manual-restart/01-restart_manual_simple.patch b/tests/incremental/04-manual-restart/01-restart_manual_simple.patch index 483ebe1bc1..c27da3c70f 100644 --- a/tests/incremental/04-manual-restart/01-restart_manual_simple.patch +++ b/tests/incremental/04-manual-restart/01-restart_manual_simple.patch @@ -15,17 +15,15 @@ index cbfb0ba70..aa83393ac 100644 return 0; } diff --git tests/incremental/04-manual-restart/01-restart_manual_simple.json tests/incremental/04-manual-restart/01-restart_manual_simple.json -index 582ede8df..51d6d31b2 100644 +index dbdb1d651..d66a6cf36 100644 --- tests/incremental/04-manual-restart/01-restart_manual_simple.json +++ tests/incremental/04-manual-restart/01-restart_manual_simple.json -@@ -9,7 +9,9 @@ - } - }, - "restart_globs": { -- "globs": [] -+ "globs": [ -+ "g" -+ ] +@@ -7,7 +7,7 @@ + "sided": { + "enabled": false + }, +- "list": [] ++ "list": ["g"] } } } diff --git a/tests/incremental/04-manual-restart/02-read_write_global.json b/tests/incremental/04-manual-restart/02-read_write_global.json index 8685ac3b70..33dd19da40 100644 --- a/tests/incremental/04-manual-restart/02-read_write_global.json +++ b/tests/incremental/04-manual-restart/02-read_write_global.json @@ -12,10 +12,8 @@ "restart": { "sided": { "enabled": false - } - }, - "restart_globs": { - "globs": [] + }, + "list": [] } } } diff --git a/tests/incremental/04-manual-restart/02-read_write_global.patch b/tests/incremental/04-manual-restart/02-read_write_global.patch index 1563f54146..2d93b2c191 100644 --- a/tests/incremental/04-manual-restart/02-read_write_global.patch +++ b/tests/incremental/04-manual-restart/02-read_write_global.patch @@ -18,15 +18,15 @@ index 8a93caabe..521322dd0 100644 int main(){ diff --git tests/incremental/04-manual-restart/02-read_write_global.json tests/incremental/04-manual-restart/02-read_write_global.json -index 8685ac3b7..b0bb607d9 100644 +index 33dd19da4..0820029df 100644 --- tests/incremental/04-manual-restart/02-read_write_global.json +++ tests/incremental/04-manual-restart/02-read_write_global.json -@@ -15,7 +15,9 @@ - } - }, - "restart_globs": { -- "globs": [] -+ "globs": [ +@@ -13,7 +13,9 @@ + "sided": { + "enabled": false + }, +- "list": [] ++ "list": [ + "g" + ] } diff --git a/tests/incremental/04-manual-restart/03-partial_contexts.json b/tests/incremental/04-manual-restart/03-partial_contexts.json index 99334fccb8..96011c8711 100644 --- a/tests/incremental/04-manual-restart/03-partial_contexts.json +++ b/tests/incremental/04-manual-restart/03-partial_contexts.json @@ -10,10 +10,8 @@ "restart": { "sided": { "enabled": false - } - }, - "restart_globs": { - "globs": [] + }, + "list": [] } } } diff --git a/tests/incremental/04-manual-restart/03-partial_contexts.patch b/tests/incremental/04-manual-restart/03-partial_contexts.patch index 295e2a5fa9..743330368c 100644 --- a/tests/incremental/04-manual-restart/03-partial_contexts.patch +++ b/tests/incremental/04-manual-restart/03-partial_contexts.patch @@ -12,15 +12,15 @@ index a2a701673..d0b4d3efc 100644 assert(x == y); return 0; diff --git tests/incremental/04-manual-restart/03-partial_contexts.json tests/incremental/04-manual-restart/03-partial_contexts.json -index 99334fccb..42a1da505 100644 +index 96011c871..0a42408a0 100644 --- tests/incremental/04-manual-restart/03-partial_contexts.json +++ tests/incremental/04-manual-restart/03-partial_contexts.json -@@ -13,7 +13,9 @@ - } - }, - "restart_globs": { -- "globs": [] -+ "globs": [ +@@ -11,7 +11,9 @@ + "sided": { + "enabled": false + }, +- "list": [] ++ "list": [ + "foo" + ] } From 42df507c8115f7ce1c6b2a15e32695ee804ce508 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Fri, 11 Feb 2022 16:37:54 +0200 Subject: [PATCH 235/402] Fix forgotten Constraints assign --- src/framework/constraints.ml | 1 - 1 file changed, 1 deletion(-) diff --git a/src/framework/constraints.ml b/src/framework/constraints.ml index 942c1a639b..204ad649ad 100644 --- a/src/framework/constraints.ml +++ b/src/framework/constraints.ml @@ -779,7 +779,6 @@ struct ; spawn = (fun v d -> failwith "Cannot \"spawn\" in query context.") ; split = (fun d es -> failwith "Cannot \"split\" in query context.") ; sideg = (fun v g -> failwith "Cannot \"split\" in query context.") - ; assign = (fun ?name _ -> failwith "Cannot \"assign\" in query context.") } in let f v = fg (GVar.spec (Obj.obj v)) in From 4bf34df3f59928d1bbf1c11f12a2070f0ca5239b Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Tue, 15 Feb 2022 16:05:49 +0200 Subject: [PATCH 236/402] Move VarQuery.Node documentation to .mli --- src/framework/varQuery.ml | 2 +- src/framework/varQuery.mli | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/framework/varQuery.ml b/src/framework/varQuery.ml index 40e856c900..28a8ea4320 100644 --- a/src/framework/varQuery.ml +++ b/src/framework/varQuery.ml @@ -1,6 +1,6 @@ type t = | Global of CilType.Varinfo.t - | Node of {node: Node.t; fundec: CilType.Fundec.t option} (** Optional [fundec] override to allow querying old state in incremental. *) + | Node of {node: Node.t; fundec: CilType.Fundec.t option} [@@deriving ord] type 'v f = 'v -> unit diff --git a/src/framework/varQuery.mli b/src/framework/varQuery.mli index 01c7eda99f..2c8c50e1ce 100644 --- a/src/framework/varQuery.mli +++ b/src/framework/varQuery.mli @@ -1,7 +1,8 @@ type t = - Global of Cil.varinfo - | Node of { node : Node.t; fundec : Cil.fundec option; } -val compare : t -> t -> int + | Global of Cil.varinfo + | Node of {node: Node.t; fundec : Cil.fundec option} (** Optional [fundec] override to allow querying old state in incremental. *) +[@@deriving ord] + type 'v f = 'v -> unit (** Takes a [Cil.file] and a list of names of globals.contents From 7528ed417de4888795f5007a2bcf75c4c6f3eb3f Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Tue, 15 Feb 2022 16:30:24 +0200 Subject: [PATCH 237/402] Derive hash for Messages.Location --- src/util/messages.ml | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/util/messages.ml b/src/util/messages.ml index ae0e14cc1c..52d3eb79b1 100644 --- a/src/util/messages.ml +++ b/src/util/messages.ml @@ -32,11 +32,7 @@ struct type t = | Node of Node0.t (** Location identified by a node. Strongly preferred, because output location updates incrementally. *) | CilLocation of CilType.Location.t (** Location identified by a literal CIL location. Strongly discouraged, because not updated incrementally. *) - [@@deriving eq] - - let hash = function - | Node node -> Node0.hash node - | CilLocation loc -> CilType.Location.hash loc + [@@deriving eq, hash] let to_cil = function | Node node -> UpdateCil0.getLoc node (* use incrementally updated location *) From a240454973c4c8b2951bfdba0ee9d328fb20496b Mon Sep 17 00:00:00 2001 From: Julian Erhard Date: Wed, 16 Feb 2022 11:57:14 +0100 Subject: [PATCH 238/402] Add test case for precision refinement with reluctant destabilization Goblint fails to prove the assertion in the incremental run. See issue #508. --- .../01-force-reanalyze/01-int-reluctant.c | 17 ++++++++++ .../01-force-reanalyze/01-int-reluctant.json | 20 ++++++++++++ .../01-force-reanalyze/01-int-reluctant.patch | 31 +++++++++++++++++++ 3 files changed, 68 insertions(+) create mode 100644 tests/incremental/01-force-reanalyze/01-int-reluctant.c create mode 100644 tests/incremental/01-force-reanalyze/01-int-reluctant.json create mode 100644 tests/incremental/01-force-reanalyze/01-int-reluctant.patch diff --git a/tests/incremental/01-force-reanalyze/01-int-reluctant.c b/tests/incremental/01-force-reanalyze/01-int-reluctant.c new file mode 100644 index 0000000000..38187f1c06 --- /dev/null +++ b/tests/incremental/01-force-reanalyze/01-int-reluctant.c @@ -0,0 +1,17 @@ +#include + +int f(int in){ + while(in < 17) { + in++; + } + assert(in == 17); //UNKNOWN + return in; +} + +int main() { + int a = 0; + assert(a); // FAIL! + a = f(a); + assert(a == 17); //UNKNOWN + return 0; +} diff --git a/tests/incremental/01-force-reanalyze/01-int-reluctant.json b/tests/incremental/01-force-reanalyze/01-int-reluctant.json new file mode 100644 index 0000000000..08361c6e43 --- /dev/null +++ b/tests/incremental/01-force-reanalyze/01-int-reluctant.json @@ -0,0 +1,20 @@ +{ + "annotation" : { + "int" : { + "enabled" : true + } + }, + "ana" : { + "int" : { + "refinement" : "fixpoint" + } + }, + "incremental" : { + "force-reanalyze" : { + "funs": ["f"] + }, + "reluctant" : { + "on": true + } + } +} diff --git a/tests/incremental/01-force-reanalyze/01-int-reluctant.patch b/tests/incremental/01-force-reanalyze/01-int-reluctant.patch new file mode 100644 index 0000000000..6f113f26a9 --- /dev/null +++ b/tests/incremental/01-force-reanalyze/01-int-reluctant.patch @@ -0,0 +1,31 @@ +--- tests/incremental/01-force-reanalyze/01-int-reluctant.c ++++ tests/incremental/01-force-reanalyze/01-int-reluctant.c +@@ -4,7 +4,7 @@ int f(int in){ + while(in < 17) { + in++; + } +- assert(in == 17); //UNKNOWN ++ assert(in == 17); + return in; + } + +@@ -12,6 +12,6 @@ int main() { + int a = 0; + assert(a); // FAIL! + a = f(a); +- assert(a == 17); //UNKNOWN ++ assert(a == 17); + return 0; + } +--- tests/incremental/01-force-reanalyze/01-int-reluctant.json ++++ tests/incremental/01-force-reanalyze/01-int-reluctant.json +@@ -2,6 +2,9 @@ + "annotation" : { + "int" : { + "enabled" : true ++ }, ++ "goblint_precision": { ++ "interval" : ["f"] + } + }, + "ana" : { From 7601be8fc0ebb75f461805530811a60ab1004c23 Mon Sep 17 00:00:00 2001 From: Julian Erhard Date: Wed, 16 Feb 2022 13:52:36 +0100 Subject: [PATCH 239/402] Set incremental.verify to false for test case, so that fix-point not reached problem is exhibited. --- .../01-force-reanalyze/01-int-reluctant.json | 5 +++-- .../01-force-reanalyze/01-int-reluctant.patch | 12 +++++++++--- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/tests/incremental/01-force-reanalyze/01-int-reluctant.json b/tests/incremental/01-force-reanalyze/01-int-reluctant.json index 08361c6e43..d58c2254bc 100644 --- a/tests/incremental/01-force-reanalyze/01-int-reluctant.json +++ b/tests/incremental/01-force-reanalyze/01-int-reluctant.json @@ -14,7 +14,8 @@ "funs": ["f"] }, "reluctant" : { - "on": true - } + "on": true + }, + "verify": false } } diff --git a/tests/incremental/01-force-reanalyze/01-int-reluctant.patch b/tests/incremental/01-force-reanalyze/01-int-reluctant.patch index 6f113f26a9..0cf9fee4ba 100644 --- a/tests/incremental/01-force-reanalyze/01-int-reluctant.patch +++ b/tests/incremental/01-force-reanalyze/01-int-reluctant.patch @@ -1,3 +1,5 @@ +diff --git tests/incremental/01-force-reanalyze/01-int-reluctant.c tests/incremental/01-force-reanalyze/01-int-reluctant.c +index 38187f1c0..6126fe8cf 100644 --- tests/incremental/01-force-reanalyze/01-int-reluctant.c +++ tests/incremental/01-force-reanalyze/01-int-reluctant.c @@ -4,7 +4,7 @@ int f(int in){ @@ -8,7 +10,7 @@ + assert(in == 17); return in; } - + @@ -12,6 +12,6 @@ int main() { int a = 0; assert(a); // FAIL! @@ -17,15 +19,19 @@ + assert(a == 17); return 0; } +diff --git tests/incremental/01-force-reanalyze/01-int-reluctant.json tests/incremental/01-force-reanalyze/01-int-reluctant.json +index d58c2254b..8834d182d 100644 --- tests/incremental/01-force-reanalyze/01-int-reluctant.json +++ tests/incremental/01-force-reanalyze/01-int-reluctant.json -@@ -2,6 +2,9 @@ +@@ -2,6 +2,11 @@ "annotation" : { "int" : { "enabled" : true + }, + "goblint_precision": { -+ "interval" : ["f"] ++ "interval": [ ++ "f" ++ ] } }, "ana" : { From 3cff7e1c5753c35f078e232f26a7a47e2f6ec32b Mon Sep 17 00:00:00 2001 From: Julian Erhard Date: Wed, 16 Feb 2022 18:03:59 +0100 Subject: [PATCH 240/402] Destabilize the entry points of force-reanalyzed functions, even when incremental.reluctant.on is activated. Force-reanalyze is intended to be used when functions are to be reanalyzed with different precision, e.g. differnt int-domains activated. Reluctant analysis (as-is) does not work for this kind of re-analysis, as the entry transfer function is not re-evaluated in the reluctant mode. Thus, this commit disables reluctant analysis for functions that are contained in the list of force analyzed functions. --- src/solvers/td3.ml | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/src/solvers/td3.ml b/src/solvers/td3.ml index 5011333a44..0fd19efe57 100644 --- a/src/solvers/td3.ml +++ b/src/solvers/td3.ml @@ -16,6 +16,8 @@ open Messages open CompareCIL open Cil +module StringSet = Set.Make(Printable.Strings) + module WP = functor (Arg: IncrSolverArg) -> functor (S:EqConstrSys) -> @@ -672,14 +674,14 @@ module WP = (* not the same as in CFG, but compares equal because of sid *) Node.Statement ({Cil.dummyStmt with sid = CfgTools.get_pseudo_return_id f}) in - let add_nodes_of_fun (functions: fundec list) withEntry = + let add_nodes_of_fun (functions: fundec list) (withEntry: fundec -> bool) = let add_stmts (f: fundec) = List.iter (fun s -> mark_node marked_for_deletion f (Statement s) ) f.sallstmts in List.iter (fun f -> - if withEntry then + if withEntry f then mark_node marked_for_deletion f (FunctionEntry f); mark_node marked_for_deletion f (Function f); add_stmts f; @@ -687,8 +689,16 @@ module WP = ) functions; in - add_nodes_of_fun changed_funs (not (GobConfig.get_bool "incremental.reluctant.on")); - add_nodes_of_fun removed_funs true; + let force_reanalyze = StringSet.of_list @@ GobConfig.get_string_list "incremental.force-reanalyze.funs" in + + let eager = (not (GobConfig.get_bool "incremental.reluctant.on")) in + let with_entry f = + (* destabilize the entry points of a changed function when reluctant is off, + or the function is to be force-reanalyzed *) + eager || StringSet.mem f.svar.vname force_reanalyze + in + add_nodes_of_fun changed_funs with_entry; + add_nodes_of_fun removed_funs (fun _ -> true); (* it is necessary to remove all unknowns for changed pseudo-returns because they have static ids *) let add_pseudo_return f un = let pseudo = dummy_pseudo_return_node f in From d2ff7fea64cec3334e41c5e1d8657cb5e06a88ca Mon Sep 17 00:00:00 2001 From: Julian Erhard Date: Thu, 17 Feb 2022 17:50:33 +0100 Subject: [PATCH 241/402] Reluctant analysis: For functions in force-analyze, destabilize entry points, avoid explicitely solving their return nodes. The reluctant analysis stores the old abstract values at the return nodes of changed functions; it omits the eager destabilization of these changed functions. Instead it calls solve on the return nodes of changed functions and checks whether the abstract state changed. For functions in force-reanalyze, a reluctant analysis should not be performed (see issue #508). This commit adapts the reluctant analysis such that the entry nodes of functions in force-reanalyze are eagerly destabilized. The call of solve on the return node of these functions can therefore be omitted. --- src/solvers/td3.ml | 52 ++++++++++++++++++++++++++-------------------- 1 file changed, 29 insertions(+), 23 deletions(-) diff --git a/src/solvers/td3.ml b/src/solvers/td3.ml index 0fd19efe57..c5376a7173 100644 --- a/src/solvers/td3.ml +++ b/src/solvers/td3.ml @@ -629,12 +629,27 @@ module WP = ) in + let force_reanalyze = StringSet.of_list @@ GobConfig.get_string_list "incremental.force-reanalyze.funs" in + let eager = (not (GobConfig.get_bool "incremental.reluctant.on")) in + let reanalyze_entry f = + (* destabilize the entry points of a changed function when reluctant is off, + or the function is to be force-reanalyzed *) + eager || StringSet.mem f.svar.vname force_reanalyze + in + let obsolete_ret = HM.create 103 in let obsolete_entry = HM.create 103 in let obsolete_prim = HM.create 103 in + + (* When reluctant is on: + Only add function entry nodes to obsolete_entry if they are in force-reanalyze *) List.iter (fun f -> - mark_node obsolete_entry f (FunctionEntry f); - mark_node obsolete_ret f (Function f); + if reanalyze_entry f then + (* collect function entry for eager destabilization *) + mark_node obsolete_entry f (FunctionEntry f) + else + (* collect function return for reluctant analysis *) + mark_node obsolete_ret f (Function f) ) changed_funs; List.iter (fun (f, pn, _) -> List.iter (fun n -> @@ -653,20 +668,19 @@ module WP = HM.replace old_ret k (old_rho, old_infl) ) ) obsolete_ret; - ) else ( - (* If reluctant destabilization is turned off we need to destabilize all nodes in completely changed functions - and the primary obsolete nodes of partly changed functions *) - print_endline "Destabilizing changed functions and primary old nodes ..."; - HM.iter (fun k _ -> - if HM.mem stable k then - destabilize k - ) obsolete_entry; - HM.iter (fun k _ -> - if HM.mem stable k then - destabilize k - ) obsolete_prim; ); + if not (HM.is_empty obsolete_entry) || not (HM.is_empty obsolete_prim) then + print_endline "Destabilizing changed functions and primary old nodes ..."; + HM.iter (fun k _ -> + if HM.mem stable k then + destabilize k + ) obsolete_entry; + HM.iter (fun k _ -> + if HM.mem stable k then + destabilize k + ) obsolete_prim; + (* We remove all unknowns for program points in changed or removed functions from rho, stable, infl and wpoint *) let marked_for_deletion = HM.create 103 in @@ -689,15 +703,7 @@ module WP = ) functions; in - let force_reanalyze = StringSet.of_list @@ GobConfig.get_string_list "incremental.force-reanalyze.funs" in - - let eager = (not (GobConfig.get_bool "incremental.reluctant.on")) in - let with_entry f = - (* destabilize the entry points of a changed function when reluctant is off, - or the function is to be force-reanalyzed *) - eager || StringSet.mem f.svar.vname force_reanalyze - in - add_nodes_of_fun changed_funs with_entry; + add_nodes_of_fun changed_funs reanalyze_entry; add_nodes_of_fun removed_funs (fun _ -> true); (* it is necessary to remove all unknowns for changed pseudo-returns because they have static ids *) let add_pseudo_return f un = From 870ddff9c6783e5acdbbc14700a18110d2638f68 Mon Sep 17 00:00:00 2001 From: Julian Erhard Date: Thu, 17 Feb 2022 18:24:53 +0100 Subject: [PATCH 242/402] Fix indentation --- src/solvers/td3.ml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/solvers/td3.ml b/src/solvers/td3.ml index c5376a7173..11c40129ce 100644 --- a/src/solvers/td3.ml +++ b/src/solvers/td3.ml @@ -642,7 +642,7 @@ module WP = let obsolete_prim = HM.create 103 in (* When reluctant is on: - Only add function entry nodes to obsolete_entry if they are in force-reanalyze *) + Only add function entry nodes to obsolete_entry if they are in force-reanalyze *) List.iter (fun f -> if reanalyze_entry f then (* collect function entry for eager destabilization *) @@ -671,7 +671,7 @@ module WP = ); if not (HM.is_empty obsolete_entry) || not (HM.is_empty obsolete_prim) then - print_endline "Destabilizing changed functions and primary old nodes ..."; + print_endline "Destabilizing changed functions and primary old nodes ..."; HM.iter (fun k _ -> if HM.mem stable k then destabilize k From 176be871aaac82030bc17eb9ef88ac3ddfe7d553 Mon Sep 17 00:00:00 2001 From: Julian Erhard Date: Thu, 17 Feb 2022 19:04:00 +0100 Subject: [PATCH 243/402] Add test for reluctant analysis with changing in-code precision annotation. This test shows that the changing the precision annotation already works, even when incremental.reluctant.on is activated; This is (probably) because the functions calling a function with changed annotations are considered changed themselves. --- .../02-reluctant-int-annotation.c | 17 +++++++++++++ .../02-reluctant-int-annotation.json | 18 +++++++++++++ .../02-reluctant-int-annotation.patch | 25 +++++++++++++++++++ 3 files changed, 60 insertions(+) create mode 100644 tests/incremental/03-precision-annotation/02-reluctant-int-annotation.c create mode 100644 tests/incremental/03-precision-annotation/02-reluctant-int-annotation.json create mode 100644 tests/incremental/03-precision-annotation/02-reluctant-int-annotation.patch diff --git a/tests/incremental/03-precision-annotation/02-reluctant-int-annotation.c b/tests/incremental/03-precision-annotation/02-reluctant-int-annotation.c new file mode 100644 index 0000000000..38187f1c06 --- /dev/null +++ b/tests/incremental/03-precision-annotation/02-reluctant-int-annotation.c @@ -0,0 +1,17 @@ +#include + +int f(int in){ + while(in < 17) { + in++; + } + assert(in == 17); //UNKNOWN + return in; +} + +int main() { + int a = 0; + assert(a); // FAIL! + a = f(a); + assert(a == 17); //UNKNOWN + return 0; +} diff --git a/tests/incremental/03-precision-annotation/02-reluctant-int-annotation.json b/tests/incremental/03-precision-annotation/02-reluctant-int-annotation.json new file mode 100644 index 0000000000..60d4692176 --- /dev/null +++ b/tests/incremental/03-precision-annotation/02-reluctant-int-annotation.json @@ -0,0 +1,18 @@ +{ + "annotation": { + "int": { + "enabled": true + } + }, + "ana": { + "int": { + "refinement": "fixpoint" + } + }, + "incremental": { + "reluctant": { + "on": true + }, + "verify": false + } +} diff --git a/tests/incremental/03-precision-annotation/02-reluctant-int-annotation.patch b/tests/incremental/03-precision-annotation/02-reluctant-int-annotation.patch new file mode 100644 index 0000000000..715a2530b9 --- /dev/null +++ b/tests/incremental/03-precision-annotation/02-reluctant-int-annotation.patch @@ -0,0 +1,25 @@ +diff --git tests/incremental/03-precision-annotation/02-reluctant-int-annotation.c tests/incremental/03-precision-annotation/02-reluctant-int-annotation.c +index 38187f1c0..698e45b62 100644 +--- tests/incremental/03-precision-annotation/02-reluctant-int-annotation.c ++++ tests/incremental/03-precision-annotation/02-reluctant-int-annotation.c +@@ -1,10 +1,11 @@ + #include + ++int f(int in) __attribute__ ((goblint_precision("def_exc", "interval"))); + int f(int in){ + while(in < 17) { + in++; + } +- assert(in == 17); //UNKNOWN ++ assert(in == 17); + return in; + } + +@@ -12,6 +13,6 @@ int main() { + int a = 0; + assert(a); // FAIL! + a = f(a); +- assert(a == 17); //UNKNOWN ++ assert(a == 17); + return 0; + } From 625818adcd6a7c00ee13a7e75a4afe7210e7756d Mon Sep 17 00:00:00 2001 From: Julian Erhard Date: Fri, 18 Feb 2022 09:13:20 +0100 Subject: [PATCH 244/402] Add unkowns from partially changed functions to obsolete_prim when reluctant is off. The set `obsolete_prim` is eagerly destablized; it does not need to be collected when reluctant is on. When reluctant is on and at the same time, some function is in force-reanalyze, this function will be considered a completely changed function, and not as partially changed. Therefore the unknowns belonging to its function entry node are collected in `obsolete_entry` beforehand; which will be eagerly destablized as required. --- src/solvers/td3.ml | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/src/solvers/td3.ml b/src/solvers/td3.ml index 11c40129ce..a3e85b9328 100644 --- a/src/solvers/td3.ml +++ b/src/solvers/td3.ml @@ -651,12 +651,15 @@ module WP = (* collect function return for reluctant analysis *) mark_node obsolete_ret f (Function f) ) changed_funs; - List.iter (fun (f, pn, _) -> - List.iter (fun n -> - mark_node obsolete_prim f n - ) pn; - mark_node obsolete_ret f (Function f); - ) part_changed_funs; + (* Unknowns from partially changed functions need only to be collected for eager destabilization when reluctant is off *) + if eager then ( + List.iter (fun (f, pn, _) -> + List.iter (fun n -> + mark_node obsolete_prim f n + ) pn; + mark_node obsolete_ret f (Function f); + ) part_changed_funs; + ); let old_ret = HM.create 103 in if GobConfig.get_bool "incremental.reluctant.on" then ( From 433b646bd0e086d1388928a4cd71c0e671bb1fd6 Mon Sep 17 00:00:00 2001 From: Julian Erhard Date: Fri, 18 Feb 2022 09:21:06 +0100 Subject: [PATCH 245/402] Query option incremental.reluctant.on only once in td3 and store it in variable --- src/solvers/td3.ml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/solvers/td3.ml b/src/solvers/td3.ml index a3e85b9328..35f533ac93 100644 --- a/src/solvers/td3.ml +++ b/src/solvers/td3.ml @@ -630,11 +630,11 @@ module WP = in let force_reanalyze = StringSet.of_list @@ GobConfig.get_string_list "incremental.force-reanalyze.funs" in - let eager = (not (GobConfig.get_bool "incremental.reluctant.on")) in + let reluctant = GobConfig.get_bool "incremental.reluctant.on" in let reanalyze_entry f = (* destabilize the entry points of a changed function when reluctant is off, or the function is to be force-reanalyzed *) - eager || StringSet.mem f.svar.vname force_reanalyze + (not reluctant) || StringSet.mem f.svar.vname force_reanalyze in let obsolete_ret = HM.create 103 in @@ -652,7 +652,7 @@ module WP = mark_node obsolete_ret f (Function f) ) changed_funs; (* Unknowns from partially changed functions need only to be collected for eager destabilization when reluctant is off *) - if eager then ( + if not reluctant then ( List.iter (fun (f, pn, _) -> List.iter (fun n -> mark_node obsolete_prim f n @@ -662,7 +662,7 @@ module WP = ); let old_ret = HM.create 103 in - if GobConfig.get_bool "incremental.reluctant.on" then ( + if reluctant then ( (* save entries of changed functions in rho for the comparison whether the result has changed after a function specific solve *) HM.iter (fun k v -> if HM.mem rho k then ( @@ -817,7 +817,7 @@ module WP = (* TODO: reluctant doesn't call destabilize on removed functions or old copies of modified functions (e.g. after removing write), so those globals don't get restarted *) - if GobConfig.get_bool "incremental.reluctant.on" then ( + if reluctant then ( (* solve on the return node of changed functions. Only destabilize the function's return node if the analysis result changed *) print_endline "Separately solving changed functions..."; let op = if GobConfig.get_string "incremental.reluctant.compare" = "leq" then S.Dom.leq else S.Dom.equal in From 2b465c3efb5451f5ce42b9393f10f8bbcc23b24c Mon Sep 17 00:00:00 2001 From: Julian Erhard Date: Fri, 18 Feb 2022 10:02:01 +0100 Subject: [PATCH 246/402] Add tests case for adding in-code precision annotation for a dynamically called function --- .../03-reluctant-int-annotation-dyn.c | 24 +++++++++++++++++ .../03-reluctant-int-annotation-dyn.json | 18 +++++++++++++ .../03-reluctant-int-annotation-dyn.patch | 26 +++++++++++++++++++ 3 files changed, 68 insertions(+) create mode 100644 tests/incremental/03-precision-annotation/03-reluctant-int-annotation-dyn.c create mode 100644 tests/incremental/03-precision-annotation/03-reluctant-int-annotation-dyn.json create mode 100644 tests/incremental/03-precision-annotation/03-reluctant-int-annotation-dyn.patch diff --git a/tests/incremental/03-precision-annotation/03-reluctant-int-annotation-dyn.c b/tests/incremental/03-precision-annotation/03-reluctant-int-annotation-dyn.c new file mode 100644 index 0000000000..58781ecd70 --- /dev/null +++ b/tests/incremental/03-precision-annotation/03-reluctant-int-annotation-dyn.c @@ -0,0 +1,24 @@ +#include + +typedef int int_to_int_fun (int); + +int f(int in){ + while(in < 17) { + in++; + } + assert(in == 17); //UNKNOWN + return in; +} + +int_to_int_fun *get_fun(){ + return &f; +} + +int main() { + int_to_int_fun *fun = get_fun(); + int a = 0; + assert(a); // FAIL! + a = fun(a); + assert(a == 17); //UNKOWN + return 0; +} diff --git a/tests/incremental/03-precision-annotation/03-reluctant-int-annotation-dyn.json b/tests/incremental/03-precision-annotation/03-reluctant-int-annotation-dyn.json new file mode 100644 index 0000000000..60d4692176 --- /dev/null +++ b/tests/incremental/03-precision-annotation/03-reluctant-int-annotation-dyn.json @@ -0,0 +1,18 @@ +{ + "annotation": { + "int": { + "enabled": true + } + }, + "ana": { + "int": { + "refinement": "fixpoint" + } + }, + "incremental": { + "reluctant": { + "on": true + }, + "verify": false + } +} diff --git a/tests/incremental/03-precision-annotation/03-reluctant-int-annotation-dyn.patch b/tests/incremental/03-precision-annotation/03-reluctant-int-annotation-dyn.patch new file mode 100644 index 0000000000..abc24f625a --- /dev/null +++ b/tests/incremental/03-precision-annotation/03-reluctant-int-annotation-dyn.patch @@ -0,0 +1,26 @@ +diff --git tests/incremental/03-precision-annotation/03-reluctant-int-annotation-dyn.c tests/incremental/03-precision-annotation/03-reluctant-int-annotation-dyn.c +index 58781ecd7..4d2620e84 100644 +--- tests/incremental/03-precision-annotation/03-reluctant-int-annotation-dyn.c ++++ tests/incremental/03-precision-annotation/03-reluctant-int-annotation-dyn.c +@@ -2,11 +2,12 @@ + + typedef int int_to_int_fun (int); + ++int f(int in) __attribute__ ((goblint_precision("def_exc", "interval"))); + int f(int in){ + while(in < 17) { + in++; + } +- assert(in == 17); //UNKNOWN ++ assert(in == 17); + return in; + } + +@@ -19,6 +20,6 @@ int main() { + int a = 0; + assert(a); // FAIL! + a = fun(a); +- assert(a == 17); //UNKOWN ++ assert(a == 17); + return 0; + } From dc01a29c12f3ec2e7cff948d9a9f39c269981f16 Mon Sep 17 00:00:00 2001 From: Julian Erhard Date: Fri, 18 Feb 2022 10:19:00 +0100 Subject: [PATCH 247/402] Add comment on why we can ommit check whether partially changed functions are partially changed. --- src/solvers/td3.ml | 1 + 1 file changed, 1 insertion(+) diff --git a/src/solvers/td3.ml b/src/solvers/td3.ml index 35f533ac93..49e88680b7 100644 --- a/src/solvers/td3.ml +++ b/src/solvers/td3.ml @@ -652,6 +652,7 @@ module WP = mark_node obsolete_ret f (Function f) ) changed_funs; (* Unknowns from partially changed functions need only to be collected for eager destabilization when reluctant is off *) + (* We utilize that force-reanalyzed functions are always considered as completely changed (and not partially changed) *) if not reluctant then ( List.iter (fun (f, pn, _) -> List.iter (fun n -> From 2e05e8837de57feb6e506924f118d8023abcfab6 Mon Sep 17 00:00:00 2001 From: Julian Erhard Date: Fri, 18 Feb 2022 17:34:24 +0100 Subject: [PATCH 248/402] Add force-reanalyze as field to change_info --- src/incremental/compareCIL.ml | 57 ++++++++++++++++++++--------------- src/solvers/td3.ml | 6 ++-- 2 files changed, 36 insertions(+), 27 deletions(-) diff --git a/src/incremental/compareCIL.ml b/src/incremental/compareCIL.ml index 470a941ff0..2f9a8a6c3c 100644 --- a/src/incremental/compareCIL.ml +++ b/src/incremental/compareCIL.ml @@ -20,45 +20,53 @@ type change_info = { mutable changed: changed_global list; mutable unchanged: global list; mutable removed: global list; - mutable added: global list + mutable added: global list; + mutable force_reanalyze: fundec list; } let empty_change_info () : change_info = - {added = []; removed = []; changed = []; unchanged = []} + {added = []; removed = []; changed = []; unchanged = []; force_reanalyze = []} + +type change_status = Unchanged | Changed | ForceReanalyze of Cil.fundec + +(** Give a boolean that indicates whether the code object is identical to the previous version, returns the corresponding [change_status]*) +let unchanged_to_change_status = function + | true -> Unchanged + | false -> Changed (* If some CFGs of the two functions to be compared are provided, a fine-grained CFG comparison is done that also determines which * nodes of the function changed. If on the other hand no CFGs are provided, the "old" AST comparison on the CIL.file is * used for functions. Then no information is collected regarding which parts/nodes of the function changed. *) -let eqF (a: Cil.fundec) (b: Cil.fundec) (cfgs : (cfg * cfg) option) = +let eqF (old: Cil.fundec) (current: Cil.fundec) (cfgs : (cfg * cfg) option) = let unchangedHeader = try - eq_varinfo a.svar b.svar && - List.for_all2 eq_varinfo a.sformals b.sformals + eq_varinfo old.svar current.svar && + List.for_all2 eq_varinfo old.sformals current.sformals with Invalid_argument _ -> false in - let identical, diffOpt = - if List.mem a.svar.vname (GobConfig.get_string_list "incremental.force-reanalyze.funs") then - false, None + let change_status, diffOpt = + if List.mem old.svar.vname (GobConfig.get_string_list "incremental.force-reanalyze.funs") then + ForceReanalyze current, None else try - let sameDef = unchangedHeader && List.for_all2 eq_varinfo a.slocals b.slocals in + let sameDef = unchangedHeader && List.for_all2 eq_varinfo old.slocals current.slocals in match cfgs with - | None -> sameDef && eq_block (a.sbody, a) (b.sbody, b), None + | None -> unchanged_to_change_status (sameDef && eq_block (old.sbody, old) (current.sbody, current)), None | Some (cfgOld, cfgNew) -> let module CfgOld : MyCFG.CfgForward = struct let next = cfgOld end in let module CfgNew : MyCFG.CfgForward = struct let next = cfgNew end in - let matches, diffNodes1, diffNodes2 = compareFun (module CfgOld) (module CfgNew) a b in - if not sameDef then (false, None) - else if diffNodes1 = [] && diffNodes2 = [] then (true, None) - else (false, Some {unchangedNodes = matches; primObsoleteNodes = diffNodes1; primNewNodes = diffNodes2}) + let matches, diffNodes1, diffNodes2 = compareFun (module CfgOld) (module CfgNew) old current in + if not sameDef then (Changed, None) + else if diffNodes1 = [] && diffNodes2 = [] then (Changed, None) + else (Changed, Some {unchangedNodes = matches; primObsoleteNodes = diffNodes1; primNewNodes = diffNodes2}) with Invalid_argument _ -> (* The combine failed because the lists have differend length *) - false, None in - identical, unchangedHeader, diffOpt + Changed, None in + change_status, unchangedHeader, diffOpt -let eq_glob (a: global) (b: global) (cfgs : (cfg * cfg) option) = match a, b with +let eq_glob (old: global) (current: global) (cfgs : (cfg * cfg) option) = match old, current with | GFun (f,_), GFun (g,_) -> eqF f g cfgs - | GVar (x, init_x, _), GVar (y, init_y, _) -> eq_varinfo x y, false, None (* ignore the init_info - a changed init of a global will lead to a different start state *) - | GVarDecl (x, _), GVarDecl (y, _) -> eq_varinfo x y, false, None - | _ -> ignore @@ Pretty.printf "Not comparable: %a and %a\n" Cil.d_global a Cil.d_global b; false, false, None + | GVar (x, init_x, _), GVar (y, init_y, _) -> unchanged_to_change_status (eq_varinfo x y), false, None (* ignore the init_info - a changed init of a global will lead to a different start state *) + | GVarDecl (x, _), GVarDecl (y, _) -> unchanged_to_change_status (eq_varinfo x y), false, None + | _ -> ignore @@ Pretty.printf "Not comparable: %a and %a\n" Cil.d_global old Cil.d_global current; Changed, false, None let compareCilFiles (oldAST: file) (newAST: file) = let cfgs = if GobConfig.get_string "incremental.compare" = "cfg" @@ -79,10 +87,11 @@ let compareCilFiles (oldAST: file) (newAST: file) = (try let old_global = GlobalMap.find ident map in (* Do a (recursive) equal comparison ignoring location information *) - let identical, unchangedHeader, diff = eq_glob old_global global cfgs in - if identical - then changes.unchanged <- global :: changes.unchanged - else changes.changed <- {current = global; old = old_global; unchangedHeader; diff} :: changes.changed + let change_status, unchangedHeader, diff = eq_glob old_global global cfgs in + match change_status with + | Changed -> changes.changed <- {current = global; old = old_global; unchangedHeader; diff} :: changes.changed + | Unchanged -> changes.unchanged <- global :: changes.unchanged + | ForceReanalyze f -> changes.force_reanalyze <- f :: changes.force_reanalyze with Not_found -> ()) with NoGlobalIdentifier _ -> () (* Global was no variable or function, it does not belong into the map *) in let checkExists map global = diff --git a/src/solvers/td3.ml b/src/solvers/td3.ml index 49e88680b7..82a15673c2 100644 --- a/src/solvers/td3.ml +++ b/src/solvers/td3.ml @@ -16,8 +16,6 @@ open Messages open CompareCIL open Cil -module StringSet = Set.Make(Printable.Strings) - module WP = functor (Arg: IncrSolverArg) -> functor (S:EqConstrSys) -> @@ -629,7 +627,9 @@ module WP = ) in - let force_reanalyze = StringSet.of_list @@ GobConfig.get_string_list "incremental.force-reanalyze.funs" in + let force_reanalyze = S.increment.changes.force_reanalyze in + + (* StringSet.of_list @@ GobConfig.get_string_list "incremental.force-reanalyze.funs" in *) let reluctant = GobConfig.get_bool "incremental.reluctant.on" in let reanalyze_entry f = (* destabilize the entry points of a changed function when reluctant is off, From a24dd863bfd79994c44ee1c8cbb7faefc0efe7d7 Mon Sep 17 00:00:00 2001 From: Julian Erhard Date: Mon, 21 Feb 2022 13:49:35 +0100 Subject: [PATCH 249/402] Add additional field for functions to be force-reanalyzed in change info. Functions are still listed in .changed, as they should be treated as changed. --- src/incremental/compareCIL.ml | 12 +++++++++--- src/solvers/td3.ml | 9 ++++----- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/src/incremental/compareCIL.ml b/src/incremental/compareCIL.ml index 2f9a8a6c3c..b27dbe056b 100644 --- a/src/incremental/compareCIL.ml +++ b/src/incremental/compareCIL.ml @@ -44,7 +44,7 @@ let eqF (old: Cil.fundec) (current: Cil.fundec) (cfgs : (cfg * cfg) option) = List.for_all2 eq_varinfo old.sformals current.sformals with Invalid_argument _ -> false in let change_status, diffOpt = - if List.mem old.svar.vname (GobConfig.get_string_list "incremental.force-reanalyze.funs") then + if List.mem current.svar.vname (GobConfig.get_string_list "incremental.force-reanalyze.funs") then ForceReanalyze current, None else try @@ -88,10 +88,16 @@ let compareCilFiles (oldAST: file) (newAST: file) = let old_global = GlobalMap.find ident map in (* Do a (recursive) equal comparison ignoring location information *) let change_status, unchangedHeader, diff = eq_glob old_global global cfgs in + let append_changed () = + changes.changed <- {current = global; old = old_global; unchangedHeader; diff} :: changes.changed + in match change_status with - | Changed -> changes.changed <- {current = global; old = old_global; unchangedHeader; diff} :: changes.changed + | Changed -> append_changed () | Unchanged -> changes.unchanged <- global :: changes.unchanged - | ForceReanalyze f -> changes.force_reanalyze <- f :: changes.force_reanalyze + | ForceReanalyze f -> + changes.force_reanalyze <- f :: changes.force_reanalyze; + append_changed (); + with Not_found -> ()) with NoGlobalIdentifier _ -> () (* Global was no variable or function, it does not belong into the map *) in let checkExists map global = diff --git a/src/solvers/td3.ml b/src/solvers/td3.ml index 82a15673c2..79f29baeb7 100644 --- a/src/solvers/td3.ml +++ b/src/solvers/td3.ml @@ -16,6 +16,8 @@ open Messages open CompareCIL open Cil +module VarinfoSet = Set.Make(CilType.Varinfo) + module WP = functor (Arg: IncrSolverArg) -> functor (S:EqConstrSys) -> @@ -627,16 +629,13 @@ module WP = ) in - let force_reanalyze = S.increment.changes.force_reanalyze in - - (* StringSet.of_list @@ GobConfig.get_string_list "incremental.force-reanalyze.funs" in *) let reluctant = GobConfig.get_bool "incremental.reluctant.on" in + let force_reanalyze = VarinfoSet.of_list (List.map (fun f -> f.svar) S.increment.changes.force_reanalyze) in let reanalyze_entry f = (* destabilize the entry points of a changed function when reluctant is off, or the function is to be force-reanalyzed *) - (not reluctant) || StringSet.mem f.svar.vname force_reanalyze + (not reluctant) || VarinfoSet.mem f.svar force_reanalyze in - let obsolete_ret = HM.create 103 in let obsolete_entry = HM.create 103 in let obsolete_prim = HM.create 103 in From 610d548b9f971b5914ac5ec0cb0b2ed4d0820a8e Mon Sep 17 00:00:00 2001 From: Julian Erhard Date: Mon, 21 Feb 2022 14:00:31 +0100 Subject: [PATCH 250/402] Fix typo in test case annotation --- .../03-precision-annotation/03-reluctant-int-annotation-dyn.c | 2 +- .../03-reluctant-int-annotation-dyn.patch | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/incremental/03-precision-annotation/03-reluctant-int-annotation-dyn.c b/tests/incremental/03-precision-annotation/03-reluctant-int-annotation-dyn.c index 58781ecd70..30391cdf61 100644 --- a/tests/incremental/03-precision-annotation/03-reluctant-int-annotation-dyn.c +++ b/tests/incremental/03-precision-annotation/03-reluctant-int-annotation-dyn.c @@ -19,6 +19,6 @@ int main() { int a = 0; assert(a); // FAIL! a = fun(a); - assert(a == 17); //UNKOWN + assert(a == 17); //UNKNOWN return 0; } diff --git a/tests/incremental/03-precision-annotation/03-reluctant-int-annotation-dyn.patch b/tests/incremental/03-precision-annotation/03-reluctant-int-annotation-dyn.patch index abc24f625a..224fd6554e 100644 --- a/tests/incremental/03-precision-annotation/03-reluctant-int-annotation-dyn.patch +++ b/tests/incremental/03-precision-annotation/03-reluctant-int-annotation-dyn.patch @@ -1,5 +1,5 @@ diff --git tests/incremental/03-precision-annotation/03-reluctant-int-annotation-dyn.c tests/incremental/03-precision-annotation/03-reluctant-int-annotation-dyn.c -index 58781ecd7..4d2620e84 100644 +index 30391cdf6..4d2620e84 100644 --- tests/incremental/03-precision-annotation/03-reluctant-int-annotation-dyn.c +++ tests/incremental/03-precision-annotation/03-reluctant-int-annotation-dyn.c @@ -2,11 +2,12 @@ @@ -20,7 +20,7 @@ index 58781ecd7..4d2620e84 100644 int a = 0; assert(a); // FAIL! a = fun(a); -- assert(a == 17); //UNKOWN +- assert(a == 17); //UNKNOWN + assert(a == 17); return 0; } From b47e01d318e2ed066b77640420bdf79e927eb0c5 Mon Sep 17 00:00:00 2001 From: Julian Erhard Date: Mon, 21 Feb 2022 14:19:57 +0100 Subject: [PATCH 251/402] Collect varinfos of force-reanalyze functions in set, instead of fundec list --- src/incremental/compareCIL.ml | 19 ++++++++++++------- src/solvers/td3.ml | 5 +---- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/src/incremental/compareCIL.ml b/src/incremental/compareCIL.ml index b27dbe056b..51f58be0ed 100644 --- a/src/incremental/compareCIL.ml +++ b/src/incremental/compareCIL.ml @@ -16,16 +16,21 @@ type changed_global = { diff: nodes_diff option } +module VarinfoSet = Set.Make(CilType.Varinfo) + type change_info = { mutable changed: changed_global list; mutable unchanged: global list; mutable removed: global list; mutable added: global list; - mutable force_reanalyze: fundec list; + + (* Set of functions that are to be force-reanalyzed. + These functions are additionally to be included in the [changed] field *) + mutable force_reanalyze: VarinfoSet.t; } let empty_change_info () : change_info = - {added = []; removed = []; changed = []; unchanged = []; force_reanalyze = []} + {added = []; removed = []; changed = []; unchanged = []; force_reanalyze = VarinfoSet.empty} type change_status = Unchanged | Changed | ForceReanalyze of Cil.fundec @@ -88,15 +93,15 @@ let compareCilFiles (oldAST: file) (newAST: file) = let old_global = GlobalMap.find ident map in (* Do a (recursive) equal comparison ignoring location information *) let change_status, unchangedHeader, diff = eq_glob old_global global cfgs in - let append_changed () = - changes.changed <- {current = global; old = old_global; unchangedHeader; diff} :: changes.changed + let append_to_changed () = + changes.changed <- {current = global; old = old_global; unchangedHeader; diff} :: changes.changed in match change_status with - | Changed -> append_changed () + | Changed -> append_to_changed () | Unchanged -> changes.unchanged <- global :: changes.unchanged | ForceReanalyze f -> - changes.force_reanalyze <- f :: changes.force_reanalyze; - append_changed (); + changes.force_reanalyze <- VarinfoSet.add f.svar changes.force_reanalyze; + append_to_changed (); with Not_found -> ()) with NoGlobalIdentifier _ -> () (* Global was no variable or function, it does not belong into the map *) in diff --git a/src/solvers/td3.ml b/src/solvers/td3.ml index 79f29baeb7..f65891539f 100644 --- a/src/solvers/td3.ml +++ b/src/solvers/td3.ml @@ -16,8 +16,6 @@ open Messages open CompareCIL open Cil -module VarinfoSet = Set.Make(CilType.Varinfo) - module WP = functor (Arg: IncrSolverArg) -> functor (S:EqConstrSys) -> @@ -630,11 +628,10 @@ module WP = in let reluctant = GobConfig.get_bool "incremental.reluctant.on" in - let force_reanalyze = VarinfoSet.of_list (List.map (fun f -> f.svar) S.increment.changes.force_reanalyze) in let reanalyze_entry f = (* destabilize the entry points of a changed function when reluctant is off, or the function is to be force-reanalyzed *) - (not reluctant) || VarinfoSet.mem f.svar force_reanalyze + (not reluctant) || CompareCIL.VarinfoSet.mem f.svar S.increment.changes.force_reanalyze in let obsolete_ret = HM.create 103 in let obsolete_entry = HM.create 103 in From fbe16e92246bfbe450cc3c2ea284113f86b89aec Mon Sep 17 00:00:00 2001 From: Julian Erhard Date: Mon, 21 Feb 2022 14:41:38 +0100 Subject: [PATCH 252/402] Fix comments in compareCIL. --- src/incremental/compareCIL.ml | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/incremental/compareCIL.ml b/src/incremental/compareCIL.ml index 51f58be0ed..b42140080c 100644 --- a/src/incremental/compareCIL.ml +++ b/src/incremental/compareCIL.ml @@ -23,10 +23,9 @@ type change_info = { mutable unchanged: global list; mutable removed: global list; mutable added: global list; - - (* Set of functions that are to be force-reanalyzed. - These functions are additionally to be included in the [changed] field *) mutable force_reanalyze: VarinfoSet.t; + (** Set of functions that are to be force-reanalyzed. + These functions are additionally included in the [changed] field, among the other changed globals. *) } let empty_change_info () : change_info = @@ -34,7 +33,7 @@ let empty_change_info () : change_info = type change_status = Unchanged | Changed | ForceReanalyze of Cil.fundec -(** Give a boolean that indicates whether the code object is identical to the previous version, returns the corresponding [change_status]*) +(** Given a boolean that indicates whether the code object is identical to the previous version, returns the corresponding [change_status]*) let unchanged_to_change_status = function | true -> Unchanged | false -> Changed From 97ca8d01a07a6d348366608ff5e0340f567c5e85 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Mon, 7 Mar 2022 12:33:50 +0200 Subject: [PATCH 253/402] Improve calculated state for undefined function warnings with IDs --- src/framework/control.ml | 2 +- src/framework/node.ml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/framework/control.ml b/src/framework/control.ml index e55dcb018f..5d00ee9e38 100644 --- a/src/framework/control.ml +++ b/src/framework/control.ml @@ -170,7 +170,7 @@ struct (* If the function is not defined, and yet has been included to the * analysis result, we generate a warning. *) with Not_found -> - Messages.warn "Calculated state for undefined function: unexpected node %a" Node.pretty_plain n + Messages.warn "Calculated state for undefined function: unexpected node %a" Node.pretty_trace n in LHT.iter add_local_var h; res diff --git a/src/framework/node.ml b/src/framework/node.ml index 8b665730f7..5123a4d76f 100644 --- a/src/framework/node.ml +++ b/src/framework/node.ml @@ -24,8 +24,8 @@ let pretty_plain_short () = function (** Pretty node for solver variable tracing with short stmt. *) let pretty_trace () = function | Statement stmt -> dprintf "node %d \"%a\"" stmt.sid Cilfacade.stmt_pretty_short stmt - | Function fd -> dprintf "call of %s" fd.svar.vname - | FunctionEntry fd -> dprintf "entry state of %s" fd.svar.vname + | Function fd -> dprintf "call of %s (%d)" fd.svar.vname fd.svar.vid + | FunctionEntry fd -> dprintf "entry state of %s (%d)" fd.svar.vname fd.svar.vid (** Output functions for Printable interface *) let pretty () x = pretty_trace () x From 7ceca645719cce2f05809ae2e0316735f9702de9 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Mon, 7 Mar 2022 12:38:14 +0200 Subject: [PATCH 254/402] Remove unnecessary initial parsing in server mode with reparse (closes #623) --- src/goblint.ml | 22 +++++++++++++++++----- src/util/server.ml | 34 +++++++++++++++++++++++++--------- 2 files changed, 42 insertions(+), 14 deletions(-) diff --git a/src/goblint.ml b/src/goblint.ml index 2bc3c769a1..835aed027b 100644 --- a/src/goblint.ml +++ b/src/goblint.ml @@ -23,18 +23,30 @@ let main () = print_endline (localtime ()); print_endline command; ); - let file = Fun.protect ~finally:GoblintDir.finalize preprocess_and_merge in - if get_bool "server.enabled" then Server.start file else ( + let file = lazy (Fun.protect ~finally:GoblintDir.finalize preprocess_and_merge) in + if get_bool "server.enabled" then ( + let file = + if get_bool "server.reparse" then + None + else + Some (Lazy.force file) + in + Server.start file + ) + else ( + let file = Lazy.force file in let changeInfo = if GobConfig.get_bool "incremental.load" || GobConfig.get_bool "incremental.save" then diff_and_rename file else - Analyses.empty_increment_data file in - file|> do_analyze changeInfo; + Analyses.empty_increment_data file + in + file |> do_analyze changeInfo; do_stats (); do_html_output (); do_gobview (); - if !verified = Some false then exit 3) (* verifier failed! *) + if !verified = Some false then exit 3 (* verifier failed! *) + ) with | Exit -> exit 1 diff --git a/src/util/server.ml b/src/util/server.ml index 7b61cbe702..c4456563e3 100644 --- a/src/util/server.ml +++ b/src/util/server.ml @@ -4,7 +4,7 @@ open Jsonrpc exception Failure of Response.Error.Code.t * string type t = { - mutable file: Cil.file; + mutable file: Cil.file option; mutable version_map: (CompareCIL.global_identifier, Cil.global) Hashtbl.t; mutable max_ids: VersionLookup.max_ids; input: IO.input; @@ -80,7 +80,11 @@ let serve serv = ) let make ?(input=stdin) ?(output=stdout) file : t = - let version_map, max_ids = VersionLookup.create_map file in + let version_map, max_ids = + match file with + | Some file -> VersionLookup.create_map file + | None -> VersionLookup.create_map Cil.dummyFile (* TODO: avoid this altogether *) + in { file; version_map; @@ -111,8 +115,19 @@ let start file = let reparse (s: t) = if GobConfig.get_bool "server.reparse" then ( GoblintDir.init (); - Fun.protect ~finally:GoblintDir.finalize Maingoblint.preprocess_and_merge, true) - else s.file, false + let file = Fun.protect ~finally:GoblintDir.finalize Maingoblint.preprocess_and_merge in + begin match s.file with + | None -> + let version_map, max_ids = VersionLookup.create_map file in + s.version_map <- version_map; + s.max_ids <- max_ids + | Some _ -> + () + end; + (file, true) + ) + else + (Option.get s.file, false) (* Only called when the file has not been reparsed, so we can skip the expensive CFG comparison. *) let virtual_changes file = @@ -124,9 +139,10 @@ let virtual_changes file = let increment_data (s: t) file reparsed = match !Serialize.server_solver_data with | Some solver_data when reparsed -> - let _, changes = VersionLookup.updateMap s.file file s.version_map in - let old_data = Some { Analyses.cil_file = s.file; solver_data } in - s.max_ids <- UpdateCil.update_ids s.file s.max_ids file s.version_map changes; + let s_file = Option.get s.file in + let _, changes = VersionLookup.updateMap s_file file s.version_map in + let old_data = Some { Analyses.cil_file = s_file; solver_data } in + s.max_ids <- UpdateCil.update_ids s_file s.max_ids file s.version_map changes; (* TODO: get globals for restarting from config *) { Analyses.changes; old_data; new_file = file; restarting = [] }, false | Some solver_data -> @@ -151,12 +167,12 @@ let analyze ?(reset=false) (s: t) = WideningThresholds.reset_lazy (); IntDomain.reset_lazy (); ApronDomain.reset_lazy (); - s.file <- file; + s.file <- Some file; GobConfig.set_bool "incremental.load" (not fresh); Fun.protect ~finally:(fun () -> GobConfig.set_bool "incremental.load" true ) (fun () -> - Maingoblint.do_analyze increment_data s.file + Maingoblint.do_analyze increment_data (Option.get s.file) ) let () = From 6b1eb9436ecccd6739acf3b4c64c510456236b68 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Mon, 7 Mar 2022 12:39:13 +0200 Subject: [PATCH 255/402] Fix server mode with reparse not updating version_map --- src/util/server.ml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/util/server.ml b/src/util/server.ml index c4456563e3..66a61a7f92 100644 --- a/src/util/server.ml +++ b/src/util/server.ml @@ -140,9 +140,10 @@ let virtual_changes file = let increment_data (s: t) file reparsed = match !Serialize.server_solver_data with | Some solver_data when reparsed -> let s_file = Option.get s.file in - let _, changes = VersionLookup.updateMap s_file file s.version_map in + let version_map, changes = VersionLookup.updateMap s_file file s.version_map in let old_data = Some { Analyses.cil_file = s_file; solver_data } in s.max_ids <- UpdateCil.update_ids s_file s.max_ids file s.version_map changes; + s.version_map <- version_map; (* TODO: get globals for restarting from config *) { Analyses.changes; old_data; new_file = file; restarting = [] }, false | Some solver_data -> From 6eb05a69df54bdf5cad75dbab143cb4c28f48a3b Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Mon, 7 Mar 2022 12:40:04 +0200 Subject: [PATCH 256/402] Add resetting of UpdateCil.location_map in server mode --- src/incremental/updateCil.ml | 2 ++ src/incremental/updateCil0.ml | 3 +++ 2 files changed, 5 insertions(+) diff --git a/src/incremental/updateCil.ml b/src/incremental/updateCil.ml index fbb29d3a30..9858916698 100644 --- a/src/incremental/updateCil.ml +++ b/src/incremental/updateCil.ml @@ -6,6 +6,8 @@ open MyCFG include UpdateCil0 let update_ids (old_file: file) (ids: max_ids) (new_file: file) (map: (global_identifier, Cil.global) Hashtbl.t) (changes: change_info) = + UpdateCil0.init (); (* reset for server mode *) + let vid_max = ref ids.max_vid in let sid_max = ref ids.max_sid in diff --git a/src/incremental/updateCil0.ml b/src/incremental/updateCil0.ml index 7a929d1883..91434a3091 100644 --- a/src/incremental/updateCil0.ml +++ b/src/incremental/updateCil0.ml @@ -4,6 +4,9 @@ module NodeMap = Hashtbl.Make(Node0) let location_map = ref (NodeMap.create 103: Cil.location NodeMap.t) +let init () = + NodeMap.clear !location_map + let getLoc (node: Node0.t) = (* In case this belongs to a changed function, we will find the true location in the map*) try From 4348dbe86ff918451119f5c66caaacf41b58640b Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Mon, 7 Mar 2022 12:41:29 +0200 Subject: [PATCH 257/402] Add Cilfacade.pseudo_return_to_fun resetting to server mode --- src/util/cilfacade.ml | 1 + 1 file changed, 1 insertion(+) diff --git a/src/util/cilfacade.ml b/src/util/cilfacade.ml index 3384302865..f6dc7151d3 100644 --- a/src/util/cilfacade.ml +++ b/src/util/cilfacade.ml @@ -490,6 +490,7 @@ let find_original_name vi = VarinfoH.find_opt (ResettableLazy.force original_nam let reset_lazy () = + StmtH.clear pseudo_return_to_fun; ResettableLazy.reset stmt_fundecs; ResettableLazy.reset varinfo_fundecs; ResettableLazy.reset name_fundecs; From 696a22d7ad55953cc8d402301f0d660a3b0c7063 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Mon, 7 Mar 2022 12:59:45 +0200 Subject: [PATCH 258/402] Improve calculated state for undefined function message --- src/framework/control.ml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/framework/control.ml b/src/framework/control.ml index 5d00ee9e38..98bacb90c1 100644 --- a/src/framework/control.ml +++ b/src/framework/control.ml @@ -170,7 +170,7 @@ struct (* If the function is not defined, and yet has been included to the * analysis result, we generate a warning. *) with Not_found -> - Messages.warn "Calculated state for undefined function: unexpected node %a" Node.pretty_trace n + Messages.debug ~category:Analyzer ~loc:(CilLocation loc) "Calculated state for undefined function: unexpected node %a" Node.pretty_trace n in LHT.iter add_local_var h; res From 8ffbdc65b7cf571d95396760205a1f4a8ac22f24 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Tue, 8 Mar 2022 16:33:08 +0200 Subject: [PATCH 259/402] Add incremental race fix test which needs global restart --- .../incremental/11-restart/12-mutex-simple.c | 23 ++++++++++++++++++ .../11-restart/12-mutex-simple.json | 9 +++++++ .../11-restart/12-mutex-simple.patch | 24 +++++++++++++++++++ 3 files changed, 56 insertions(+) create mode 100644 tests/incremental/11-restart/12-mutex-simple.c create mode 100644 tests/incremental/11-restart/12-mutex-simple.json create mode 100644 tests/incremental/11-restart/12-mutex-simple.patch diff --git a/tests/incremental/11-restart/12-mutex-simple.c b/tests/incremental/11-restart/12-mutex-simple.c new file mode 100644 index 0000000000..82c1642a93 --- /dev/null +++ b/tests/incremental/11-restart/12-mutex-simple.c @@ -0,0 +1,23 @@ +#include +#include + +int myglobal; +pthread_mutex_t mutex1 = PTHREAD_MUTEX_INITIALIZER; +pthread_mutex_t mutex2 = PTHREAD_MUTEX_INITIALIZER; + +void *t_fun(void *arg) { + pthread_mutex_lock(&mutex1); + myglobal=myglobal+1; // RACE! + pthread_mutex_unlock(&mutex1); + return NULL; +} + +int main(void) { + pthread_t id; + pthread_create(&id, NULL, t_fun, NULL); + pthread_mutex_lock(&mutex2); + myglobal=myglobal+1; // RACE! + pthread_mutex_unlock(&mutex2); + pthread_join (id, NULL); + return 0; +} diff --git a/tests/incremental/11-restart/12-mutex-simple.json b/tests/incremental/11-restart/12-mutex-simple.json new file mode 100644 index 0000000000..daff0678ce --- /dev/null +++ b/tests/incremental/11-restart/12-mutex-simple.json @@ -0,0 +1,9 @@ +{ + "incremental": { + "restart": { + "sided": { + "enabled": false + } + } + } +} \ No newline at end of file diff --git a/tests/incremental/11-restart/12-mutex-simple.patch b/tests/incremental/11-restart/12-mutex-simple.patch new file mode 100644 index 0000000000..14913c581d --- /dev/null +++ b/tests/incremental/11-restart/12-mutex-simple.patch @@ -0,0 +1,24 @@ +--- tests/incremental/11-restart/12-mutex-simple.c ++++ tests/incremental/11-restart/12-mutex-simple.c +@@ -7,7 +7,7 @@ pthread_mutex_t mutex2 = PTHREAD_MUTEX_INITIALIZER; + + void *t_fun(void *arg) { + pthread_mutex_lock(&mutex1); +- myglobal=myglobal+1; // RACE! ++ myglobal=myglobal+1; // NORACE + pthread_mutex_unlock(&mutex1); + return NULL; + } +@@ -15,9 +15,9 @@ void *t_fun(void *arg) { + int main(void) { + pthread_t id; + pthread_create(&id, NULL, t_fun, NULL); +- pthread_mutex_lock(&mutex2); +- myglobal=myglobal+1; // RACE! +- pthread_mutex_unlock(&mutex2); ++ pthread_mutex_lock(&mutex1); ++ myglobal=myglobal+1; // NORACE ++ pthread_mutex_unlock(&mutex1); + pthread_join (id, NULL); + return 0; + } From fa99c7bf7a91f9a0cef764e97de4e31503325416 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Tue, 8 Mar 2022 16:33:30 +0200 Subject: [PATCH 260/402] Disable dbg.compare_runs.glob in test-incremental.sh --- scripts/test-incremental.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/test-incremental.sh b/scripts/test-incremental.sh index 29198669ac..fa95f25f42 100755 --- a/scripts/test-incremental.sh +++ b/scripts/test-incremental.sh @@ -19,7 +19,7 @@ patch -p0 -b <$patch ./goblint --conf $conf $args --enable incremental.load --set save_run $base/$test-incrementalrun $source &> $base/$test.after.incr.log ./goblint --conf $conf $args --enable incremental.only-rename --set save_run $base/$test-originalrun $source &> $base/$test.after.scratch.log -./goblint --conf $conf --enable solverdiffs --compare_runs $base/$test-originalrun $base/$test-incrementalrun $source +./goblint --conf $conf --disable dbg.compare_runs.glob --enable solverdiffs --compare_runs $base/$test-originalrun $base/$test-incrementalrun $source patch -p0 -b -R <$patch rm -r $base/$test-originalrun $base/$test-incrementalrun From 05ef1969f0b5fe7a5722b31eb02464e3685fc201 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Tue, 8 Mar 2022 16:36:43 +0200 Subject: [PATCH 261/402] Add TD3 incremental sided restart fuel for limiting transitivity --- src/solvers/td3.ml | 37 ++++++++++++------- src/util/options.schema.json | 6 +++ .../11-restart/12-mutex-simple.json | 3 +- 3 files changed, 32 insertions(+), 14 deletions(-) diff --git a/src/solvers/td3.ml b/src/solvers/td3.ml index f65891539f..8de600b27c 100644 --- a/src/solvers/td3.ml +++ b/src/solvers/td3.ml @@ -543,7 +543,8 @@ module WP = in (* destabilize which restarts side-effected vars *) - let rec destabilize_with_side ?(front=true) x = + (* side_fuel specifies how many times (in recursion depth) to destabilize side_infl, None means infinite *) + let rec destabilize_with_side ~side_fuel ?(front=true) x = if tracing then trace "sol2" "destabilize_with_side %a\n" S.Var.pretty_trace x; (* is side-effected var (global/function entry)? *) @@ -563,7 +564,7 @@ module WP = if tracing then trace "sol2" "stable remove %a\n" S.Var.pretty_trace y; HM.remove stable y; HM.remove superstable y; - destabilize_with_side ~front:false y + destabilize_with_side ~side_fuel ~front:false y ) w ); @@ -576,25 +577,35 @@ module WP = if tracing then trace "sol2" "stable remove %a\n" S.Var.pretty_trace y; HM.remove stable y; HM.remove superstable y; - destabilize_with_side ~front:false y + destabilize_with_side ~side_fuel ~front:false y ) w; (* destabilize side infl *) let w = HM.find_default side_infl x VS.empty in HM.remove side_infl x; - (* TODO: should this also be conditional on restart_only_globals? right now goes through function entry side effects, but just doesn't restart them *) - VS.iter (fun y -> - if tracing then trace "sol2" "destabilize_with_side %a side_infl %a\n" S.Var.pretty_trace x S.Var.pretty_trace y; - if tracing then trace "sol2" "stable remove %a\n" S.Var.pretty_trace y; - HM.remove stable y; - HM.remove superstable y; - destabilize_with_side ~front:false y - ) w + + if side_fuel <> Some 0 then ( (* non-0 or infinite fuel is fine *) + let side_fuel' = Option.map Int.pred side_fuel in + (* TODO: should this also be conditional on restart_only_globals? right now goes through function entry side effects, but just doesn't restart them *) + VS.iter (fun y -> + if tracing then trace "sol2" "destabilize_with_side %a side_infl %a\n" S.Var.pretty_trace x S.Var.pretty_trace y; + if tracing then trace "sol2" "stable remove %a\n" S.Var.pretty_trace y; + HM.remove stable y; + HM.remove superstable y; + destabilize_with_side ~side_fuel:side_fuel' ~front:false y + ) w + ) in destabilize_ref := - if restart_sided then - destabilize_with_side + if restart_sided then ( + let side_fuel = + match GobConfig.get_int "incremental.restart.sided.fuel" with + | fuel when fuel >= 0 -> Some fuel + | _ -> None (* infinite *) + in + destabilize_with_side ~side_fuel + ) else destabilize_normal; diff --git a/src/util/options.schema.json b/src/util/options.schema.json index c858c7767b..bc23e12bec 100644 --- a/src/util/options.schema.json +++ b/src/util/options.schema.json @@ -961,6 +961,12 @@ "description": "TODO", "type": "boolean", "default": false + }, + "fuel": { + "title": "incremental.restart.sided.fuel", + "description": "TODO", + "type": "integer", + "default": -1 } }, "additionalProperties": false diff --git a/tests/incremental/11-restart/12-mutex-simple.json b/tests/incremental/11-restart/12-mutex-simple.json index daff0678ce..ec32980a50 100644 --- a/tests/incremental/11-restart/12-mutex-simple.json +++ b/tests/incremental/11-restart/12-mutex-simple.json @@ -2,7 +2,8 @@ "incremental": { "restart": { "sided": { - "enabled": false + "enabled": true, + "fuel": 1 } } } From c88f534ae1184932a3846f4cea25e8a83983b393 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 9 Mar 2022 10:49:34 +0200 Subject: [PATCH 262/402] Add incremental tests with fuel for going through wrapper function --- .../11-restart/13-mutex-simple-wrap2.c | 27 +++++++++++++++++++ .../11-restart/13-mutex-simple-wrap2.json | 10 +++++++ .../11-restart/13-mutex-simple-wrap2.patch | 22 +++++++++++++++ .../11-restart/14-mutex-simple-wrap1.c | 27 +++++++++++++++++++ .../11-restart/14-mutex-simple-wrap1.json | 10 +++++++ .../11-restart/14-mutex-simple-wrap1.patch | 22 +++++++++++++++ 6 files changed, 118 insertions(+) create mode 100644 tests/incremental/11-restart/13-mutex-simple-wrap2.c create mode 100644 tests/incremental/11-restart/13-mutex-simple-wrap2.json create mode 100644 tests/incremental/11-restart/13-mutex-simple-wrap2.patch create mode 100644 tests/incremental/11-restart/14-mutex-simple-wrap1.c create mode 100644 tests/incremental/11-restart/14-mutex-simple-wrap1.json create mode 100644 tests/incremental/11-restart/14-mutex-simple-wrap1.patch diff --git a/tests/incremental/11-restart/13-mutex-simple-wrap2.c b/tests/incremental/11-restart/13-mutex-simple-wrap2.c new file mode 100644 index 0000000000..53ff298524 --- /dev/null +++ b/tests/incremental/11-restart/13-mutex-simple-wrap2.c @@ -0,0 +1,27 @@ +#include +#include + +int myglobal; +pthread_mutex_t mutex1 = PTHREAD_MUTEX_INITIALIZER; +pthread_mutex_t mutex2 = PTHREAD_MUTEX_INITIALIZER; + +void *t_fun(void *arg) { + pthread_mutex_lock(&mutex1); + myglobal=myglobal+1; // RACE! + pthread_mutex_unlock(&mutex1); + return NULL; +} + +void wrap() { + pthread_mutex_lock(&mutex2); + myglobal=myglobal+1; // RACE! + pthread_mutex_unlock(&mutex2); +} + +int main(void) { + pthread_t id; + pthread_create(&id, NULL, t_fun, NULL); + wrap(); + pthread_join (id, NULL); + return 0; +} diff --git a/tests/incremental/11-restart/13-mutex-simple-wrap2.json b/tests/incremental/11-restart/13-mutex-simple-wrap2.json new file mode 100644 index 0000000000..7775710988 --- /dev/null +++ b/tests/incremental/11-restart/13-mutex-simple-wrap2.json @@ -0,0 +1,10 @@ +{ + "incremental": { + "restart": { + "sided": { + "enabled": true, + "fuel": 2 + } + } + } +} \ No newline at end of file diff --git a/tests/incremental/11-restart/13-mutex-simple-wrap2.patch b/tests/incremental/11-restart/13-mutex-simple-wrap2.patch new file mode 100644 index 0000000000..075513aea3 --- /dev/null +++ b/tests/incremental/11-restart/13-mutex-simple-wrap2.patch @@ -0,0 +1,22 @@ +--- tests/incremental/11-restart/13-mutex-simple-wrap2.c ++++ tests/incremental/11-restart/13-mutex-simple-wrap2.c +@@ -7,15 +7,15 @@ pthread_mutex_t mutex2 = PTHREAD_MUTEX_INITIALIZER; + + void *t_fun(void *arg) { + pthread_mutex_lock(&mutex1); +- myglobal=myglobal+1; // RACE! ++ myglobal=myglobal+1; // NORACE + pthread_mutex_unlock(&mutex1); + return NULL; + } + + void wrap() { +- pthread_mutex_lock(&mutex2); +- myglobal=myglobal+1; // RACE! +- pthread_mutex_unlock(&mutex2); ++ pthread_mutex_lock(&mutex1); ++ myglobal=myglobal+1; // NORACE ++ pthread_mutex_unlock(&mutex1); + } + + int main(void) { diff --git a/tests/incremental/11-restart/14-mutex-simple-wrap1.c b/tests/incremental/11-restart/14-mutex-simple-wrap1.c new file mode 100644 index 0000000000..53ff298524 --- /dev/null +++ b/tests/incremental/11-restart/14-mutex-simple-wrap1.c @@ -0,0 +1,27 @@ +#include +#include + +int myglobal; +pthread_mutex_t mutex1 = PTHREAD_MUTEX_INITIALIZER; +pthread_mutex_t mutex2 = PTHREAD_MUTEX_INITIALIZER; + +void *t_fun(void *arg) { + pthread_mutex_lock(&mutex1); + myglobal=myglobal+1; // RACE! + pthread_mutex_unlock(&mutex1); + return NULL; +} + +void wrap() { + pthread_mutex_lock(&mutex2); + myglobal=myglobal+1; // RACE! + pthread_mutex_unlock(&mutex2); +} + +int main(void) { + pthread_t id; + pthread_create(&id, NULL, t_fun, NULL); + wrap(); + pthread_join (id, NULL); + return 0; +} diff --git a/tests/incremental/11-restart/14-mutex-simple-wrap1.json b/tests/incremental/11-restart/14-mutex-simple-wrap1.json new file mode 100644 index 0000000000..ec32980a50 --- /dev/null +++ b/tests/incremental/11-restart/14-mutex-simple-wrap1.json @@ -0,0 +1,10 @@ +{ + "incremental": { + "restart": { + "sided": { + "enabled": true, + "fuel": 1 + } + } + } +} \ No newline at end of file diff --git a/tests/incremental/11-restart/14-mutex-simple-wrap1.patch b/tests/incremental/11-restart/14-mutex-simple-wrap1.patch new file mode 100644 index 0000000000..191f1771f9 --- /dev/null +++ b/tests/incremental/11-restart/14-mutex-simple-wrap1.patch @@ -0,0 +1,22 @@ +--- tests/incremental/11-restart/14-mutex-simple-wrap1.c ++++ tests/incremental/11-restart/14-mutex-simple-wrap1.c +@@ -7,15 +7,15 @@ pthread_mutex_t mutex2 = PTHREAD_MUTEX_INITIALIZER; + + void *t_fun(void *arg) { + pthread_mutex_lock(&mutex1); +- myglobal=myglobal+1; // RACE! ++ myglobal=myglobal+1; // RACE (not enough fuel) + pthread_mutex_unlock(&mutex1); + return NULL; + } + + void wrap() { +- pthread_mutex_lock(&mutex2); +- myglobal=myglobal+1; // RACE! +- pthread_mutex_unlock(&mutex2); ++ pthread_mutex_lock(&mutex1); ++ myglobal=myglobal+1; // RACE (not enough fuel) ++ pthread_mutex_unlock(&mutex1); + } + + int main(void) { From efc092ba68d9b858886800c59da28bb798dbb5f3 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 9 Mar 2022 11:07:32 +0200 Subject: [PATCH 263/402] Add option incremental.restart.sided.fuel-only-global Request from https://github.com/goblint/analyzer/pull/629#issuecomment-1062625125. --- src/solvers/td3.ml | 11 ++++++-- src/util/options.schema.json | 6 +++++ .../11-restart/15-mutex-simple-wrap1-global.c | 27 +++++++++++++++++++ .../15-mutex-simple-wrap1-global.json | 11 ++++++++ .../15-mutex-simple-wrap1-global.patch | 22 +++++++++++++++ 5 files changed, 75 insertions(+), 2 deletions(-) create mode 100644 tests/incremental/11-restart/15-mutex-simple-wrap1-global.c create mode 100644 tests/incremental/11-restart/15-mutex-simple-wrap1-global.json create mode 100644 tests/incremental/11-restart/15-mutex-simple-wrap1-global.patch diff --git a/src/solvers/td3.ml b/src/solvers/td3.ml index 8de600b27c..dd31a4e44f 100644 --- a/src/solvers/td3.ml +++ b/src/solvers/td3.ml @@ -542,10 +542,12 @@ module WP = () in + let restart_fuel_only_globals = GobConfig.get_bool "incremental.restart.sided.fuel-only-global" in + (* destabilize which restarts side-effected vars *) (* side_fuel specifies how many times (in recursion depth) to destabilize side_infl, None means infinite *) let rec destabilize_with_side ~side_fuel ?(front=true) x = - if tracing then trace "sol2" "destabilize_with_side %a\n" S.Var.pretty_trace x; + if tracing then trace "sol2" "destabilize_with_side %a %a\n" S.Var.pretty_trace x (Pretty.docOpt (Pretty.dprintf "%d")) side_fuel; (* is side-effected var (global/function entry)? *) let w = HM.find_default side_dep x VS.empty in @@ -585,7 +587,12 @@ module WP = HM.remove side_infl x; if side_fuel <> Some 0 then ( (* non-0 or infinite fuel is fine *) - let side_fuel' = Option.map Int.pred side_fuel in + let side_fuel' = + if not restart_fuel_only_globals || Node.equal (S.Var.node x) (Function Cil.dummyFunDec) then + Option.map Int.pred side_fuel + else + side_fuel (* don't decrease fuel for function entry side effect *) + in (* TODO: should this also be conditional on restart_only_globals? right now goes through function entry side effects, but just doesn't restart them *) VS.iter (fun y -> if tracing then trace "sol2" "destabilize_with_side %a side_infl %a\n" S.Var.pretty_trace x S.Var.pretty_trace y; diff --git a/src/util/options.schema.json b/src/util/options.schema.json index bc23e12bec..012192166f 100644 --- a/src/util/options.schema.json +++ b/src/util/options.schema.json @@ -967,6 +967,12 @@ "description": "TODO", "type": "integer", "default": -1 + }, + "fuel-only-global": { + "title": "incremental.restart.sided.fuel-only-global", + "description": "TODO", + "type": "boolean", + "default": false } }, "additionalProperties": false diff --git a/tests/incremental/11-restart/15-mutex-simple-wrap1-global.c b/tests/incremental/11-restart/15-mutex-simple-wrap1-global.c new file mode 100644 index 0000000000..53ff298524 --- /dev/null +++ b/tests/incremental/11-restart/15-mutex-simple-wrap1-global.c @@ -0,0 +1,27 @@ +#include +#include + +int myglobal; +pthread_mutex_t mutex1 = PTHREAD_MUTEX_INITIALIZER; +pthread_mutex_t mutex2 = PTHREAD_MUTEX_INITIALIZER; + +void *t_fun(void *arg) { + pthread_mutex_lock(&mutex1); + myglobal=myglobal+1; // RACE! + pthread_mutex_unlock(&mutex1); + return NULL; +} + +void wrap() { + pthread_mutex_lock(&mutex2); + myglobal=myglobal+1; // RACE! + pthread_mutex_unlock(&mutex2); +} + +int main(void) { + pthread_t id; + pthread_create(&id, NULL, t_fun, NULL); + wrap(); + pthread_join (id, NULL); + return 0; +} diff --git a/tests/incremental/11-restart/15-mutex-simple-wrap1-global.json b/tests/incremental/11-restart/15-mutex-simple-wrap1-global.json new file mode 100644 index 0000000000..b597867546 --- /dev/null +++ b/tests/incremental/11-restart/15-mutex-simple-wrap1-global.json @@ -0,0 +1,11 @@ +{ + "incremental": { + "restart": { + "sided": { + "enabled": true, + "fuel": 1, + "fuel-only-global": true + } + } + } +} \ No newline at end of file diff --git a/tests/incremental/11-restart/15-mutex-simple-wrap1-global.patch b/tests/incremental/11-restart/15-mutex-simple-wrap1-global.patch new file mode 100644 index 0000000000..4d0c246660 --- /dev/null +++ b/tests/incremental/11-restart/15-mutex-simple-wrap1-global.patch @@ -0,0 +1,22 @@ +--- tests/incremental/11-restart/15-mutex-simple-wrap1-global.c ++++ tests/incremental/11-restart/15-mutex-simple-wrap1-global.c +@@ -7,15 +7,15 @@ pthread_mutex_t mutex2 = PTHREAD_MUTEX_INITIALIZER; + + void *t_fun(void *arg) { + pthread_mutex_lock(&mutex1); +- myglobal=myglobal+1; // RACE! ++ myglobal=myglobal+1; // NORACE + pthread_mutex_unlock(&mutex1); + return NULL; + } + + void wrap() { +- pthread_mutex_lock(&mutex2); +- myglobal=myglobal+1; // RACE! +- pthread_mutex_unlock(&mutex2); ++ pthread_mutex_lock(&mutex1); ++ myglobal=myglobal+1; // NORACE ++ pthread_mutex_unlock(&mutex1); + } + + int main(void) { From 4ac2da7580d2fc94076a9b757866c16943e6551d Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 9 Mar 2022 18:48:13 +0200 Subject: [PATCH 264/402] Remove unused Basetype.Variables functions --- src/cdomains/basetype.ml | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/cdomains/basetype.ml b/src/cdomains/basetype.ml index 4db41612cf..bfe3a592d2 100644 --- a/src/cdomains/basetype.ml +++ b/src/cdomains/basetype.ml @@ -40,8 +40,6 @@ struct | _ -> Local let name () = "variables" let printXml f x = BatPrintf.fprintf f "\n\n%s\n\n\n" (XmlUtil.escape (show x)) - let var_id _ = "globals" - let node _ = MyCFG.Function Cil.dummyFunDec let arbitrary () = MyCheck.Arbitrary.varinfo end From e122956b0404f541060d97d5e043c6403bd64d4e Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 10 Mar 2022 12:33:43 +0200 Subject: [PATCH 265/402] Add write-only sides rho to optimize access restarting --- src/analyses/accessAnalysis.ml | 1 + src/framework/analyses.ml | 2 +- src/framework/constraints.ml | 2 +- src/solvers/postSolver.ml | 43 ++++++++++++++++++++-------------- src/solvers/td3.ml | 42 ++++++++++++++++++++++++++++----- 5 files changed, 64 insertions(+), 26 deletions(-) diff --git a/src/analyses/accessAnalysis.ml b/src/analyses/accessAnalysis.ml index a646d9d3a1..88b3dfec18 100644 --- a/src/analyses/accessAnalysis.ml +++ b/src/analyses/accessAnalysis.ml @@ -25,6 +25,7 @@ struct module V = struct include Printable.Either (V0) (CilType.Varinfo) + let name () = "access" (* HACK: incremental accesses rely on this! *) let access x = `Left x let vars x = `Right x end diff --git a/src/framework/analyses.ml b/src/framework/analyses.ml index b71371e051..5183113cf0 100644 --- a/src/framework/analyses.ml +++ b/src/framework/analyses.ml @@ -71,7 +71,7 @@ struct let contexts x = `Right x (* from Basetype.Variables *) - let var_id _ = "globals" + let var_id = show (* HACK: incremental accesses rely on this! *) let node _ = MyCFG.Function Cil.dummyFunDec let pretty_trace = pretty end diff --git a/src/framework/constraints.ml b/src/framework/constraints.ml index 204ad649ad..14543ec4b6 100644 --- a/src/framework/constraints.ml +++ b/src/framework/constraints.ml @@ -808,7 +808,7 @@ module EqIncrSolverFromEqSolver (Sol: GenericEqBoxSolver): GenericEqBoxIncrSolve let solve box xs vs = let vh = Sol.solve box xs vs in - Post.post xs vs vh; + Post.post xs vs vh (VH.create 0); (vh, ()) end diff --git a/src/solvers/postSolver.ml b/src/solvers/postSolver.ml index 4b6e016f03..9c7b0810f6 100644 --- a/src/solvers/postSolver.ml +++ b/src/solvers/postSolver.ml @@ -9,8 +9,8 @@ sig module VH: Hashtbl.S with type key = S.v val init: unit -> unit - val one_side: vh:S.Dom.t VH.t -> x:S.v -> y:S.v -> d:S.Dom.t -> unit - val one_constraint: vh:S.Dom.t VH.t -> x:S.v -> rhs:S.Dom.t -> unit + val one_side: vh:S.Dom.t VH.t -> vhw:S.Dom.t VH.t VH.t -> x:S.v -> y:S.v -> d:S.Dom.t -> unit + val one_constraint: vh:S.Dom.t VH.t -> vhw:S.Dom.t VH.t VH.t -> x:S.v -> rhs:S.Dom.t -> unit val finalize: vh:S.Dom.t VH.t -> reachable:unit VH.t -> unit end @@ -26,8 +26,8 @@ module Unit: F = module S = S module VH = VH let init () = () - let one_side ~vh ~x ~y ~d = () - let one_constraint ~vh ~x ~rhs = () + let one_side ~vh ~vhw ~x ~y ~d = () + let one_constraint ~vh ~vhw ~x ~rhs = () let finalize ~vh ~reachable = () end @@ -40,12 +40,12 @@ struct let init () = PS1.init (); PS2.init () - let one_side ~vh ~x ~y ~d = - PS1.one_side ~vh ~x ~y ~d; - PS2.one_side ~vh ~x ~y ~d - let one_constraint ~vh ~x ~rhs = - PS1.one_constraint ~vh ~x ~rhs; - PS2.one_constraint ~vh ~x ~rhs + let one_side ~vh ~vhw ~x ~y ~d = + PS1.one_side ~vh ~vhw ~x ~y ~d; + PS2.one_side ~vh ~vhw ~x ~y ~d + let one_constraint ~vh ~vhw ~x ~rhs = + PS1.one_constraint ~vh ~vhw ~x ~rhs; + PS2.one_constraint ~vh ~vhw ~x ~rhs let finalize ~vh ~reachable = PS1.finalize ~vh ~reachable; PS2.finalize ~vh ~reachable @@ -83,14 +83,21 @@ module Verify: F = Goblintutil.verified := Some false; ignore (Pretty.printf "Fixpoint not reached at %a\nOrigin: %a\n @[Solver computed:\n%a\nSide-effect:\n%a\nDifference: %a\n@]" S.Var.pretty_trace y S.Var.pretty_trace x S.Dom.pretty lhs S.Dom.pretty rhs S.Dom.pretty_diff (rhs, lhs)) - let one_side ~vh ~x ~y ~d = + let one_side ~vh ~vhw ~x ~y ~d = + (* HACK: incremental accesses insanity! *) + (* ignore (Pretty.printf "one_side %s: %a\n" (S.Var.var_id y) S.Dom.pretty d); *) + let is_acc = String.starts_with (S.Var.var_id y) "access:" in let y_lhs = try VH.find vh y with Not_found -> S.Dom.bot () in - if not (S.Dom.leq d y_lhs) then + if is_acc then ( + VH.replace vh y (S.Dom.join y_lhs d); + VH.modify_def (VH.create 1) x (fun w -> VH.add w y d; w) vhw (* inner add intentional *) + ) + else if not (S.Dom.leq d y_lhs) then complain_side x y ~lhs:y_lhs ~rhs:d else VH.replace vh y (S.Dom.join y_lhs d) (* HACK: allow warnings/accesses to be added *) - let one_constraint ~vh ~x ~rhs = + let one_constraint ~vh ~vhw ~x ~rhs = let lhs = try VH.find vh x with Not_found -> S.Dom.bot () in if not (S.Dom.leq rhs lhs) then complain_constraint x ~lhs ~rhs @@ -173,7 +180,7 @@ struct module S = PS.S module VH = PS.VH - let post xs vs vh = + let post xs vs vh vhw = if get_bool "dbg.verbose" then print_endline "Postsolving\n"; @@ -200,12 +207,12 @@ struct try VH.find vh y with Not_found -> S.Dom.bot () in let set y d = - PS.one_side ~vh ~x ~y ~d; + PS.one_side ~vh ~vhw ~x ~y ~d; (* check before recursing *) one_var y in let rhs = f get set in - PS.one_constraint ~vh ~x ~rhs + PS.one_constraint ~vh ~vhw ~x ~rhs in List.iter one_var vs; @@ -252,7 +259,7 @@ struct in Some (List.reduce compose postsolvers) - let post xs vs vh = + let post xs vs vh vhw = match postsolver_opt with | None -> () | Some (module PS) -> @@ -263,7 +270,7 @@ struct end in let module M = MakeIncr (IncrPS) in - M.post xs vs vh + M.post xs vs vh vhw end (** Make complete (non-incremental) postsolving function from list of postsolvers. diff --git a/src/solvers/td3.ml b/src/solvers/td3.ml index f65891539f..adc5016fc8 100644 --- a/src/solvers/td3.ml +++ b/src/solvers/td3.ml @@ -34,6 +34,7 @@ module WP = mutable side_dep: VS.t HM.t; (** Dependencies of side-effected variables. Knowing these allows restarting them and re-triggering all side effects. *) mutable side_infl: VS.t HM.t; (** Influences to side-effected variables. Not normally in [infl], but used for restarting them. *) mutable var_messages: Message.t HM.t; + mutable rho_write: S.Dom.t HM.t HM.t; } type marshal = solver_data @@ -48,6 +49,7 @@ module WP = side_dep = HM.create 10; side_infl = HM.create 10; var_messages = HM.create 10; + rho_write = HM.create 10; } let print_data data str = @@ -130,6 +132,7 @@ module WP = let superstable = HM.copy stable in let var_messages = data.var_messages in + let rho_write = data.rho_write in let abort = GobConfig.get_bool "solvers.td3.abort" in let destab_infl = HM.create 10 in @@ -955,16 +958,27 @@ module WP = struct include PostSolver.Unit (S) (HM) - let one_side ~vh ~x ~y ~d = + let one_side ~vh ~vhw ~x ~y ~d = HM.replace side_dep y (VS.add x (try HM.find side_dep y with Not_found -> VS.empty)); HM.replace side_infl x (VS.add y (try HM.find side_infl x with Not_found -> VS.empty)); end in - if incr_verify then - HM.filteri_inplace (fun x _ -> HM.mem superstable x) var_messages - else + (* restart write-only *) + HM.iter (fun x w -> + HM.iter (fun y d -> + HM.replace rho y (S.Dom.bot ()); + ) w + ) rho_write; + + if incr_verify then ( + HM.filteri_inplace (fun x _ -> HM.mem superstable x) var_messages; + HM.filteri_inplace (fun x _ -> HM.mem superstable x) rho_write + ) + else ( HM.clear var_messages; + HM.clear rho_write + ); let module IncrWarn: PostSolver.S with module S = S and module VH = HM = struct @@ -978,6 +992,13 @@ module WP = HM.iter (fun _ m -> Messages.add m ) var_messages; + (* retrigger *) + HM.iter (fun x w -> + HM.iter (fun y d -> + let old_d = try HM.find rho y with Not_found -> S.Dom.bot () in + HM.replace rho y (S.Dom.join old_d d) + ) w + ) rho_write ); (* hook to collect new messages *) @@ -1009,11 +1030,11 @@ module WP = let module Post = PostSolver.MakeIncrList (MakeIncrListArg) in - Post.post st vs rho; + Post.post st vs rho rho_write; print_data data "Data after postsolve"; - {st; infl; sides; rho; wpoint; stable; side_dep; side_infl; var_messages} + {st; infl; sides; rho; wpoint; stable; side_dep; side_infl; var_messages; rho_write} let solve box st vs = let reuse_stable = GobConfig.get_bool "incremental.stable" in @@ -1078,6 +1099,15 @@ module WP = HM.add var_messages' (S.Var.relift k) v (* var_messages contains duplicate keys, so must add not replace! *) ) data.var_messages; data.var_messages <- var_messages'; + let rho_write' = HM.create (HM.length data.rho_write) in + HM.iter (fun x w -> + let w' = HM.create (HM.length w) in + HM.iter (fun y d -> + HM.replace w' (S.Var.relift y) (S.Dom.relift d) + ) w; + HM.replace rho_write' (S.Var.relift x) w'; + ) data.rho_write; + data.rho_write <- rho_write'; ); if not reuse_stable then ( print_endline "Destabilizing everything!"; From 490c4d62c4b779614ef8cd1b98e0b2f498c3d68e Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 10 Mar 2022 12:52:39 +0200 Subject: [PATCH 266/402] Add is_write_only function to solver unknowns --- src/analyses/accessAnalysis.ml | 3 +- src/analyses/apron/apronAnalysis.apron.ml | 6 +- src/analyses/arinc.ml | 6 +- src/analyses/base.ml | 1 + src/analyses/extract_arinc.ml | 6 +- src/analyses/mCP.ml | 4 +- src/analyses/mCPRegistry.ml | 89 ++++++++++++++++++++++- src/analyses/mutexAnalysis.ml | 6 +- src/analyses/region.ml | 6 +- src/analyses/threadAnalysis.ml | 6 +- src/analyses/threadJoins.ml | 6 +- src/domains/printable.ml | 6 ++ src/framework/analyses.ml | 17 ++++- src/framework/constraints.ml | 7 ++ src/solvers/postSolver.ml | 6 +- 15 files changed, 154 insertions(+), 21 deletions(-) diff --git a/src/analyses/accessAnalysis.ml b/src/analyses/accessAnalysis.ml index 88b3dfec18..68a0fe5053 100644 --- a/src/analyses/accessAnalysis.ml +++ b/src/analyses/accessAnalysis.ml @@ -25,9 +25,10 @@ struct module V = struct include Printable.Either (V0) (CilType.Varinfo) - let name () = "access" (* HACK: incremental accesses rely on this! *) + let name () = "access" let access x = `Left x let vars x = `Right x + let is_write_only _ = true end module V0Set = SetDomain.Make (V0) diff --git a/src/analyses/apron/apronAnalysis.apron.ml b/src/analyses/apron/apronAnalysis.apron.ml index 1ca0d81e61..69a20833f6 100644 --- a/src/analyses/apron/apronAnalysis.apron.ml +++ b/src/analyses/apron/apronAnalysis.apron.ml @@ -16,7 +16,11 @@ struct module D = ApronComponents (AD) (Priv.D) module G = Priv.G module C = D - module V = Priv.V + module V = + struct + include Priv.V + let is_write_only _ = false + end open AD open (ApronDomain: (sig module V: (module type of ApronDomain.V) end)) (* open only V from ApronDomain (to shadow V of Spec), but don't open D (to not shadow D here) *) diff --git a/src/analyses/arinc.ml b/src/analyses/arinc.ml index fe2679cc50..b2b70fdacb 100644 --- a/src/analyses/arinc.ml +++ b/src/analyses/arinc.ml @@ -91,7 +91,11 @@ struct module Tasks = SetDomain.Make (Lattice.Prod (Queries.LS) (ArincDomain.D)) (* set of created tasks to spawn when going multithreaded *) module G = Tasks module C = D - module V = Printable.UnitConf (struct let name = "tasks" end) + module V = + struct + include Printable.UnitConf (struct let name = "tasks" end) + let is_write_only _ = false + end let context fd d = { d with pred = Pred.bot (); ctx = Ctx.bot () } diff --git a/src/analyses/base.ml b/src/analyses/base.ml index c351083e54..7a3d3bba8b 100644 --- a/src/analyses/base.ml +++ b/src/analyses/base.ml @@ -47,6 +47,7 @@ struct include Printable.Either (Priv.V) (ThreadIdDomain.Thread) let priv x = `Left x let thread x = `Right x + let is_write_only _ = false end module G = diff --git a/src/analyses/extract_arinc.ml b/src/analyses/extract_arinc.ml index 03a231bcc4..1faeee50cc 100644 --- a/src/analyses/extract_arinc.ml +++ b/src/analyses/extract_arinc.ml @@ -33,7 +33,11 @@ struct module C = D module Tasks = SetDomain.Make (Lattice.Prod (Queries.LS) (D)) (* set of created tasks to spawn when going multithreaded *) module G = Tasks - module V = Printable.UnitConf (struct let name = "tasks" end) + module V = + struct + include Printable.UnitConf (struct let name = "tasks" end) + let is_write_only _ = false + end type pname = string (* process name *) type fname = string (* function name *) diff --git a/src/analyses/mCP.ml b/src/analyses/mCP.ml index 8b0aa92ae9..a136f278e6 100644 --- a/src/analyses/mCP.ml +++ b/src/analyses/mCP.ml @@ -13,12 +13,12 @@ module MCP2 : Analyses.Spec with module D = DomListLattice (LocalDomainListSpec) and module G = DomVariantLattice (GlobalDomainListSpec) and module C = DomListPrintable (ContextListSpec) - and module V = DomVariantPrintable (VarListSpec) = + and module V = DomVariantPrintableW (VarListSpec) = struct module D = DomListLattice (LocalDomainListSpec) module G = DomVariantLattice (GlobalDomainListSpec) module C = DomListPrintable (ContextListSpec) - module V = DomVariantPrintable (VarListSpec) + module V = DomVariantPrintableW (VarListSpec) open List open Obj let v_of n v = (n, repr v) diff --git a/src/analyses/mCPRegistry.ml b/src/analyses/mCPRegistry.ml index 57e03dff5b..0e9d49b061 100644 --- a/src/analyses/mCPRegistry.ml +++ b/src/analyses/mCPRegistry.ml @@ -7,7 +7,7 @@ type spec_modules = { name : string ; dom : (module Lattice.S) ; glob : (module Lattice.S) ; cont : (module Printable.S) - ; var : (module Printable.S) + ; var : (module Printable.W) ; acc : (module MCPA) } let activated : (int * spec_modules) list ref = ref [] @@ -25,7 +25,7 @@ let register_analysis = ; dom = (module S.D : Lattice.S) ; glob = (module S.G : Lattice.S) ; cont = (module S.C : Printable.S) - ; var = (module S.V : Printable.S) + ; var = (module S.V : Printable.W) ; acc = (module S.A : MCPA) } in @@ -45,6 +45,12 @@ sig val domain_list : unit -> (int * (module Printable.S)) list end +module type DomainListPrintableWSpec = +sig + val assoc_dom : int -> (module Printable.W) + val domain_list : unit -> (int * (module Printable.W)) list +end + module type DomainListMCPASpec = sig val assoc_dom : int -> (module MCPA) @@ -239,6 +245,83 @@ struct QCheck.oneof arbs end +(* TODO: deduplicate *) +module DomVariantPrintableW (DLSpec : DomainListPrintableWSpec) + : Printable.W with type t = int * unknown += +struct + include Printable.Std (* for default invariant, tag, ... *) + + open DLSpec + open List + open Obj + + type t = int * unknown + + let unop_map f ((n, d):t) = + f n (assoc_dom n) d + + let pretty () = unop_map (fun n (module S: Printable.W) x -> + Pretty.dprintf "%s:%a" (S.name ()) S.pretty (obj x) + ) + + let show = unop_map (fun n (module S: Printable.W) x -> + let analysis_name = find_spec_name n in + analysis_name ^ ":" ^ S.show (obj x) + ) + + let is_write_only = unop_map (fun n (module S: Printable.W) x -> + S.is_write_only (obj x) + ) + + let to_yojson x = + `Assoc [ + unop_map (fun n (module S: Printable.W) x -> + let name = find_spec_name n in + (name, S.to_yojson (obj x)) + ) x + ] + + let equal (n1, x1) (n2, x2) = + n1 = n2 && ( + let module S = (val assoc_dom n1) in + S.equal (obj x1) (obj x2) + ) + + let compare (n1, x1) (n2, x2) = + let r = Stdlib.compare n1 n2 in + if r <> 0 then + r + else + let module S = (val assoc_dom n1) in + S.compare (obj x1) (obj x2) + + let hash = unop_map (fun n (module S: Printable.W) x -> + Hashtbl.hash (n, S.hash (obj x)) + ) + + let name () = + let domain_name (n, (module S: Printable.W)) = + let analysis_name = find_spec_name n in + analysis_name ^ ":" ^ S.name () + in + IO.to_string (List.print ~first:"" ~last:"" ~sep:" | " String.print) (map domain_name @@ domain_list ()) + + let printXml f = unop_map (fun n (module S: Printable.W) x -> + BatPrintf.fprintf f "\n" (find_spec_name n); + S.printXml f (obj x); + BatPrintf.fprintf f "\n" + ) + + let invariant c = unop_map (fun n (module S: Printable.W) x -> + S.invariant c (obj x) + ) + + let arbitrary () = + let arbs = map (fun (n, (module S: Printable.W)) -> QCheck.map ~rev:(fun (_, o) -> obj o) (fun x -> (n, repr x)) @@ S.arbitrary ()) @@ domain_list () in + QCheck.oneof arbs +end + module DomListLattice (DLSpec : DomainListLatticeSpec) : Lattice.S with type t = (int * unknown) list = @@ -339,7 +422,7 @@ struct let domain_list () = List.map (fun (n,p) -> n, p.cont) !activated_ctx_sens end -module VarListSpec : DomainListPrintableSpec = +module VarListSpec : DomainListPrintableWSpec = struct let assoc_dom n = (find_spec n).var let domain_list () = List.map (fun (n,p) -> n, p.var) !activated diff --git a/src/analyses/mutexAnalysis.ml b/src/analyses/mutexAnalysis.ml index 806d7be280..3451f43b46 100644 --- a/src/analyses/mutexAnalysis.ml +++ b/src/analyses/mutexAnalysis.ml @@ -34,7 +34,11 @@ struct (** We do not add global state, so just lift from [BS]*) module G = P.G - module V = VarinfoV + module V = + struct + include VarinfoV + let is_write_only _ = false + end let should_join x y = D.equal x y diff --git a/src/analyses/region.ml b/src/analyses/region.ml index 9c326117de..a2c5a4d963 100644 --- a/src/analyses/region.ml +++ b/src/analyses/region.ml @@ -14,7 +14,11 @@ struct module D = RegionDomain.RegionDom module G = RegPart module C = D - module V = Printable.UnitConf (struct let name = "partitions" end) + module V = + struct + include Printable.UnitConf (struct let name = "partitions" end) + let is_write_only _ = false + end let regions exp part st : Lval.CilLval.t list = match st with diff --git a/src/analyses/threadAnalysis.ml b/src/analyses/threadAnalysis.ml index 184395f50a..4951d1cd9b 100644 --- a/src/analyses/threadAnalysis.ml +++ b/src/analyses/threadAnalysis.ml @@ -14,7 +14,11 @@ struct module D = ConcDomain.CreatedThreadSet module C = D module G = ConcDomain.ThreadCreation - module V = T + module V = + struct + include T + let is_write_only _ = false + end let should_join = D.equal diff --git a/src/analyses/threadJoins.ml b/src/analyses/threadJoins.ml index ad7ed42379..c2e680571b 100644 --- a/src/analyses/threadJoins.ml +++ b/src/analyses/threadJoins.ml @@ -14,7 +14,11 @@ struct module D = MustTIDs module C = D module G = MustTIDs - module V = TID + module V = + struct + include TID + let is_write_only _ = false + end (* transfer functions *) let return ctx (exp:exp option) (f:fundec) : D.t = diff --git a/src/domains/printable.ml b/src/domains/printable.ml index d95d0e78c1..291ecf1f2b 100644 --- a/src/domains/printable.ml +++ b/src/domains/printable.ml @@ -32,6 +32,12 @@ sig val relift: t -> t end +module type W = +sig + include S + val is_write_only: t -> bool (* TODO: move elsewhere *) +end + module Empty: S = struct type t = | [@@deriving eq, ord, hash] diff --git a/src/framework/analyses.ml b/src/framework/analyses.ml index 5183113cf0..fb70515883 100644 --- a/src/framework/analyses.ml +++ b/src/framework/analyses.ml @@ -21,6 +21,7 @@ sig val printXml : 'a BatInnerIO.output -> t -> unit val var_id : t -> string val node : t -> MyCFG.node + val is_write_only: t -> bool val relift : t -> t (* needed only for incremental+hashcons to re-hashcons contexts after loading *) end @@ -62,18 +63,22 @@ struct let var_id (n,_) = Var.var_id n let node (n,_) = n + let is_write_only _ = false end -module GVarF (V: Printable.S) = +module GVarF (V: Printable.W) = struct include Printable.Either (V) (CilType.Fundec) let spec x = `Left x let contexts x = `Right x (* from Basetype.Variables *) - let var_id = show (* HACK: incremental accesses rely on this! *) + let var_id = show let node _ = MyCFG.Function Cil.dummyFunDec let pretty_trace = pretty + let is_write_only = function + | `Left x -> V.is_write_only x + | `Right _ -> true end module GVarG (G: Lattice.S) (C: Printable.S) = @@ -366,7 +371,7 @@ sig module D : Lattice.S module G : Lattice.S module C : Printable.S - module V: Printable.S (** Global constraint variables. *) + module V: Printable.W (** Global constraint variables. *) val name : unit -> string @@ -557,7 +562,11 @@ struct end module VarinfoV = CilType.Varinfo (* TODO: or Basetype.Variables? *) -module EmptyV = Printable.Empty +module EmptyV = +struct + include Printable.Empty + let is_write_only _ = false +end module UnitA = struct diff --git a/src/framework/constraints.ml b/src/framework/constraints.ml index 14543ec4b6..5c6c1b1f21 100644 --- a/src/framework/constraints.ml +++ b/src/framework/constraints.ml @@ -839,6 +839,10 @@ struct let node = function | `L a -> LV.node a | `G a -> GV.node a + + let is_write_only = function + | `L a -> LV.is_write_only a + | `G a -> GV.is_write_only a end (** Translate a [GlobConstrSys] into a [EqConstrSys] *) @@ -1107,6 +1111,9 @@ struct include Printable.Either (S.V) (Node) let s x = `Left x let node x = `Right x + let is_write_only = function + | `Left x -> S.V.is_write_only x + | `Right _ -> true end module EM = diff --git a/src/solvers/postSolver.ml b/src/solvers/postSolver.ml index 9c7b0810f6..bbedb604a9 100644 --- a/src/solvers/postSolver.ml +++ b/src/solvers/postSolver.ml @@ -84,11 +84,9 @@ module Verify: F = ignore (Pretty.printf "Fixpoint not reached at %a\nOrigin: %a\n @[Solver computed:\n%a\nSide-effect:\n%a\nDifference: %a\n@]" S.Var.pretty_trace y S.Var.pretty_trace x S.Dom.pretty lhs S.Dom.pretty rhs S.Dom.pretty_diff (rhs, lhs)) let one_side ~vh ~vhw ~x ~y ~d = - (* HACK: incremental accesses insanity! *) - (* ignore (Pretty.printf "one_side %s: %a\n" (S.Var.var_id y) S.Dom.pretty d); *) - let is_acc = String.starts_with (S.Var.var_id y) "access:" in let y_lhs = try VH.find vh y with Not_found -> S.Dom.bot () in - if is_acc then ( + if S.Var.is_write_only y then ( + (* HACK: incremental accesses etc insanity! *) VH.replace vh y (S.Dom.join y_lhs d); VH.modify_def (VH.create 1) x (fun w -> VH.add w y d; w) vhw (* inner add intentional *) ) From 7ffb6c81f5b744c05002414566c970cabca54723 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 10 Mar 2022 13:01:15 +0200 Subject: [PATCH 267/402] Remove postsolving write-only validation hacks --- src/analyses/accessAnalysis.ml | 20 ++++---------------- src/framework/analyses.ml | 1 - src/framework/constraints.ml | 15 +++------------ src/solvers/postSolver.ml | 2 -- 4 files changed, 7 insertions(+), 31 deletions(-) diff --git a/src/analyses/accessAnalysis.ml b/src/analyses/accessAnalysis.ml index 68a0fe5053..e8d4b720e3 100644 --- a/src/analyses/accessAnalysis.ml +++ b/src/analyses/accessAnalysis.ml @@ -46,8 +46,6 @@ struct | _ -> failwith "Access.vars" let create_access access = `Lifted1 access let create_vars vars = `Lifted2 vars - - let leq x y = !GU.postsolving || leq x y (* HACK: to pass verify*) end let safe = ref 0 @@ -62,24 +60,14 @@ struct let side_vars ctx lv_opt ty = match lv_opt with | Some (v, _) -> - let d = - if !GU.should_warn then - G.create_vars (V0Set.singleton (lv_opt, ty)) - else - G.bot () (* HACK: just to pass validation with MCP DomVariantLattice *) - in - ctx.sideg (V.vars v) d; + if !GU.should_warn then + ctx.sideg (V.vars v) (G.create_vars (V0Set.singleton (lv_opt, ty))) | None -> () let side_access ctx ty lv_opt (conf, w, loc, e, a) = - let d = - if !GU.should_warn then - G.create_access (Access.AS.singleton (conf, w, loc, e, a)) - else - G.bot () (* HACK: just to pass validation with MCP DomVariantLattice *) - in - ctx.sideg (V.access (lv_opt, ty)) d; + if !GU.should_warn then + ctx.sideg (V.access (lv_opt, ty)) (G.create_access (Access.AS.singleton (conf, w, loc, e, a))); side_vars ctx lv_opt ty let do_access (ctx: (D.t, G.t, C.t, V.t) ctx) (w:bool) (reach:bool) (conf:int) (e:exp) = diff --git a/src/framework/analyses.ml b/src/framework/analyses.ml index fb70515883..9cb6235584 100644 --- a/src/framework/analyses.ml +++ b/src/framework/analyses.ml @@ -91,7 +91,6 @@ struct let printXml f c = BatPrintf.fprintf f "%a" printXml c (* wrap in for HTML printing *) end ) - let leq x y = !GU.postsolving || leq x y (* HACK: to pass verify*) end include Lattice.Lift2 (G) (CSet) (Printable.DefaultNames) diff --git a/src/framework/constraints.ml b/src/framework/constraints.ml index 5c6c1b1f21..d6f6a0d37b 100644 --- a/src/framework/constraints.ml +++ b/src/framework/constraints.ml @@ -484,13 +484,8 @@ struct | _ -> S.sync ctx `Normal let side_context sideg f c = - let d = - if !GU.postsolving then - G.create_contexts (G.CSet.singleton c) - else - G.create_contexts (G.CSet.empty ()) (* HACK: just to pass validation with MCP DomVariantLattice *) - in - sideg (GVar.contexts f) d + if !GU.postsolving then + sideg (GVar.contexts f) (G.create_contexts (G.CSet.singleton c)) let common_ctx var edge prev_node pval (getl:lv -> ld) sidel getg sideg : (D.t, S.G.t, S.C.t, S.V.t) ctx * D.t list ref * (lval option * varinfo * exp list * D.t) list ref = let r = ref [] in @@ -1116,11 +1111,7 @@ struct | `Right _ -> true end - module EM = - struct - include MapDomain.MapBot (Basetype.CilExp) (Basetype.Bools) - let leq x y = !GU.postsolving || leq x y (* HACK: to pass verify*) - end + module EM = MapDomain.MapBot (Basetype.CilExp) (Basetype.Bools) module G = struct diff --git a/src/solvers/postSolver.ml b/src/solvers/postSolver.ml index bbedb604a9..db6f074174 100644 --- a/src/solvers/postSolver.ml +++ b/src/solvers/postSolver.ml @@ -92,8 +92,6 @@ module Verify: F = ) else if not (S.Dom.leq d y_lhs) then complain_side x y ~lhs:y_lhs ~rhs:d - else - VH.replace vh y (S.Dom.join y_lhs d) (* HACK: allow warnings/accesses to be added *) let one_constraint ~vh ~vhw ~x ~rhs = let lhs = try VH.find vh x with Not_found -> S.Dom.bot () in From 4e4bd9e556ef36be8bbf344238c2b50115412b72 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 10 Mar 2022 14:24:51 +0200 Subject: [PATCH 268/402] Rename Printable.W -> Analyses.SpecSysVar --- src/analyses/mCPRegistry.ml | 28 ++++++++++++++-------------- src/domains/printable.ml | 6 ------ src/framework/analyses.ml | 18 +++++++++++++++--- 3 files changed, 29 insertions(+), 23 deletions(-) diff --git a/src/analyses/mCPRegistry.ml b/src/analyses/mCPRegistry.ml index 0e9d49b061..bda4b1059f 100644 --- a/src/analyses/mCPRegistry.ml +++ b/src/analyses/mCPRegistry.ml @@ -7,7 +7,7 @@ type spec_modules = { name : string ; dom : (module Lattice.S) ; glob : (module Lattice.S) ; cont : (module Printable.S) - ; var : (module Printable.W) + ; var : (module SpecSysVar) ; acc : (module MCPA) } let activated : (int * spec_modules) list ref = ref [] @@ -25,7 +25,7 @@ let register_analysis = ; dom = (module S.D : Lattice.S) ; glob = (module S.G : Lattice.S) ; cont = (module S.C : Printable.S) - ; var = (module S.V : Printable.W) + ; var = (module S.V : SpecSysVar) ; acc = (module S.A : MCPA) } in @@ -47,8 +47,8 @@ end module type DomainListPrintableWSpec = sig - val assoc_dom : int -> (module Printable.W) - val domain_list : unit -> (int * (module Printable.W)) list + val assoc_dom : int -> (module SpecSysVar) + val domain_list : unit -> (int * (module SpecSysVar)) list end module type DomainListMCPASpec = @@ -247,7 +247,7 @@ end (* TODO: deduplicate *) module DomVariantPrintableW (DLSpec : DomainListPrintableWSpec) - : Printable.W with type t = int * unknown + : SpecSysVar with type t = int * unknown = struct include Printable.Std (* for default invariant, tag, ... *) @@ -261,22 +261,22 @@ struct let unop_map f ((n, d):t) = f n (assoc_dom n) d - let pretty () = unop_map (fun n (module S: Printable.W) x -> + let pretty () = unop_map (fun n (module S: SpecSysVar) x -> Pretty.dprintf "%s:%a" (S.name ()) S.pretty (obj x) ) - let show = unop_map (fun n (module S: Printable.W) x -> + let show = unop_map (fun n (module S: SpecSysVar) x -> let analysis_name = find_spec_name n in analysis_name ^ ":" ^ S.show (obj x) ) - let is_write_only = unop_map (fun n (module S: Printable.W) x -> + let is_write_only = unop_map (fun n (module S: SpecSysVar) x -> S.is_write_only (obj x) ) let to_yojson x = `Assoc [ - unop_map (fun n (module S: Printable.W) x -> + unop_map (fun n (module S: SpecSysVar) x -> let name = find_spec_name n in (name, S.to_yojson (obj x)) ) x @@ -296,29 +296,29 @@ struct let module S = (val assoc_dom n1) in S.compare (obj x1) (obj x2) - let hash = unop_map (fun n (module S: Printable.W) x -> + let hash = unop_map (fun n (module S: SpecSysVar) x -> Hashtbl.hash (n, S.hash (obj x)) ) let name () = - let domain_name (n, (module S: Printable.W)) = + let domain_name (n, (module S: SpecSysVar)) = let analysis_name = find_spec_name n in analysis_name ^ ":" ^ S.name () in IO.to_string (List.print ~first:"" ~last:"" ~sep:" | " String.print) (map domain_name @@ domain_list ()) - let printXml f = unop_map (fun n (module S: Printable.W) x -> + let printXml f = unop_map (fun n (module S: SpecSysVar) x -> BatPrintf.fprintf f "\n" (find_spec_name n); S.printXml f (obj x); BatPrintf.fprintf f "\n" ) - let invariant c = unop_map (fun n (module S: Printable.W) x -> + let invariant c = unop_map (fun n (module S: SpecSysVar) x -> S.invariant c (obj x) ) let arbitrary () = - let arbs = map (fun (n, (module S: Printable.W)) -> QCheck.map ~rev:(fun (_, o) -> obj o) (fun x -> (n, repr x)) @@ S.arbitrary ()) @@ domain_list () in + let arbs = map (fun (n, (module S: SpecSysVar)) -> QCheck.map ~rev:(fun (_, o) -> obj o) (fun x -> (n, repr x)) @@ S.arbitrary ()) @@ domain_list () in QCheck.oneof arbs end diff --git a/src/domains/printable.ml b/src/domains/printable.ml index 291ecf1f2b..d95d0e78c1 100644 --- a/src/domains/printable.ml +++ b/src/domains/printable.ml @@ -32,12 +32,6 @@ sig val relift: t -> t end -module type W = -sig - include S - val is_write_only: t -> bool (* TODO: move elsewhere *) -end - module Empty: S = struct type t = | [@@deriving eq, ord, hash] diff --git a/src/framework/analyses.ml b/src/framework/analyses.ml index 9cb6235584..d3282baa9a 100644 --- a/src/framework/analyses.ml +++ b/src/framework/analyses.ml @@ -12,16 +12,22 @@ module M = Messages * other functions. *) type fundecs = fundec list * fundec list * fundec list +module type SysVar = +sig + type t + val is_write_only: t -> bool +end + module type VarType = sig include Hashtbl.HashedType + include SysVar with type t := t val pretty_trace: unit -> t -> doc val compare : t -> t -> int val printXml : 'a BatInnerIO.output -> t -> unit val var_id : t -> string val node : t -> MyCFG.node - val is_write_only: t -> bool val relift : t -> t (* needed only for incremental+hashcons to re-hashcons contexts after loading *) end @@ -66,7 +72,13 @@ struct let is_write_only _ = false end -module GVarF (V: Printable.W) = +module type SpecSysVar = +sig + include Printable.S + include SysVar with type t := t +end + +module GVarF (V: SpecSysVar) = struct include Printable.Either (V) (CilType.Fundec) let spec x = `Left x @@ -370,7 +382,7 @@ sig module D : Lattice.S module G : Lattice.S module C : Printable.S - module V: Printable.W (** Global constraint variables. *) + module V: SpecSysVar (** Global constraint variables. *) val name : unit -> string From 75caf5438585ad04ce323af3ac2d1d1e37f20a6f Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 10 Mar 2022 14:29:12 +0200 Subject: [PATCH 269/402] Extract default is_write_only to StdV --- src/analyses/apron/apronAnalysis.apron.ml | 2 +- src/analyses/arinc.ml | 2 +- src/analyses/base.ml | 2 +- src/analyses/extract_arinc.ml | 2 +- src/analyses/mutexAnalysis.ml | 6 +----- src/analyses/region.ml | 2 +- src/analyses/threadAnalysis.ml | 2 +- src/analyses/threadJoins.ml | 2 +- src/framework/analyses.ml | 14 ++++++++++++-- 9 files changed, 20 insertions(+), 14 deletions(-) diff --git a/src/analyses/apron/apronAnalysis.apron.ml b/src/analyses/apron/apronAnalysis.apron.ml index 69a20833f6..3846afd31b 100644 --- a/src/analyses/apron/apronAnalysis.apron.ml +++ b/src/analyses/apron/apronAnalysis.apron.ml @@ -19,7 +19,7 @@ struct module V = struct include Priv.V - let is_write_only _ = false + include StdV end open AD diff --git a/src/analyses/arinc.ml b/src/analyses/arinc.ml index b2b70fdacb..78fb97f8b3 100644 --- a/src/analyses/arinc.ml +++ b/src/analyses/arinc.ml @@ -94,7 +94,7 @@ struct module V = struct include Printable.UnitConf (struct let name = "tasks" end) - let is_write_only _ = false + include StdV end let context fd d = { d with pred = Pred.bot (); ctx = Ctx.bot () } diff --git a/src/analyses/base.ml b/src/analyses/base.ml index 7a3d3bba8b..85188a20b7 100644 --- a/src/analyses/base.ml +++ b/src/analyses/base.ml @@ -47,7 +47,7 @@ struct include Printable.Either (Priv.V) (ThreadIdDomain.Thread) let priv x = `Left x let thread x = `Right x - let is_write_only _ = false + include StdV end module G = diff --git a/src/analyses/extract_arinc.ml b/src/analyses/extract_arinc.ml index 1faeee50cc..32b4eb7e03 100644 --- a/src/analyses/extract_arinc.ml +++ b/src/analyses/extract_arinc.ml @@ -36,7 +36,7 @@ struct module V = struct include Printable.UnitConf (struct let name = "tasks" end) - let is_write_only _ = false + include StdV end type pname = string (* process name *) diff --git a/src/analyses/mutexAnalysis.ml b/src/analyses/mutexAnalysis.ml index 3451f43b46..806d7be280 100644 --- a/src/analyses/mutexAnalysis.ml +++ b/src/analyses/mutexAnalysis.ml @@ -34,11 +34,7 @@ struct (** We do not add global state, so just lift from [BS]*) module G = P.G - module V = - struct - include VarinfoV - let is_write_only _ = false - end + module V = VarinfoV let should_join x y = D.equal x y diff --git a/src/analyses/region.ml b/src/analyses/region.ml index a2c5a4d963..f062ffbb1a 100644 --- a/src/analyses/region.ml +++ b/src/analyses/region.ml @@ -17,7 +17,7 @@ struct module V = struct include Printable.UnitConf (struct let name = "partitions" end) - let is_write_only _ = false + include StdV end let regions exp part st : Lval.CilLval.t list = diff --git a/src/analyses/threadAnalysis.ml b/src/analyses/threadAnalysis.ml index 4951d1cd9b..fabf2c3b3d 100644 --- a/src/analyses/threadAnalysis.ml +++ b/src/analyses/threadAnalysis.ml @@ -17,7 +17,7 @@ struct module V = struct include T - let is_write_only _ = false + include StdV end let should_join = D.equal diff --git a/src/analyses/threadJoins.ml b/src/analyses/threadJoins.ml index c2e680571b..4638f6417e 100644 --- a/src/analyses/threadJoins.ml +++ b/src/analyses/threadJoins.ml @@ -17,7 +17,7 @@ struct module V = struct include TID - let is_write_only _ = false + include StdV end (* transfer functions *) diff --git a/src/framework/analyses.ml b/src/framework/analyses.ml index d3282baa9a..50cb13d3dd 100644 --- a/src/framework/analyses.ml +++ b/src/framework/analyses.ml @@ -572,11 +572,21 @@ struct BatPrintf.fprintf f "\n%a\n%a" C.printXml c D.printXml d end -module VarinfoV = CilType.Varinfo (* TODO: or Basetype.Variables? *) +module StdV = +struct + let is_write_only _ = false +end + +module VarinfoV = +struct + include CilType.Varinfo (* TODO: or Basetype.Variables? *) + include StdV +end + module EmptyV = struct include Printable.Empty - let is_write_only _ = false + include StdV end module UnitA = From 92fd35f33ce7420cc6a364fd7da034a3bba2874d Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 10 Mar 2022 14:35:23 +0200 Subject: [PATCH 270/402] Deduplicate DomVariantSysVar --- src/analyses/mCP.ml | 4 +- src/analyses/mCPRegistry.ml | 80 ++++++++----------------------------- 2 files changed, 18 insertions(+), 66 deletions(-) diff --git a/src/analyses/mCP.ml b/src/analyses/mCP.ml index a136f278e6..ad3731b9ad 100644 --- a/src/analyses/mCP.ml +++ b/src/analyses/mCP.ml @@ -13,12 +13,12 @@ module MCP2 : Analyses.Spec with module D = DomListLattice (LocalDomainListSpec) and module G = DomVariantLattice (GlobalDomainListSpec) and module C = DomListPrintable (ContextListSpec) - and module V = DomVariantPrintableW (VarListSpec) = + and module V = DomVariantSysVar (VarListSpec) = struct module D = DomListLattice (LocalDomainListSpec) module G = DomVariantLattice (GlobalDomainListSpec) module C = DomListPrintable (ContextListSpec) - module V = DomVariantPrintableW (VarListSpec) + module V = DomVariantSysVar (VarListSpec) open List open Obj let v_of n v = (n, repr v) diff --git a/src/analyses/mCPRegistry.ml b/src/analyses/mCPRegistry.ml index bda4b1059f..89f1f16d8a 100644 --- a/src/analyses/mCPRegistry.ml +++ b/src/analyses/mCPRegistry.ml @@ -45,7 +45,7 @@ sig val domain_list : unit -> (int * (module Printable.S)) list end -module type DomainListPrintableWSpec = +module type DomainListSysVarSpec = sig val assoc_dom : int -> (module SpecSysVar) val domain_list : unit -> (int * (module SpecSysVar)) list @@ -87,6 +87,18 @@ struct List.map (fun (x,y) -> (x,f y)) (D.domain_list ()) end +module PrintableOfSysVarSpec (D:DomainListSysVarSpec) : DomainListPrintableSpec = +struct + let assoc_dom n = + let f (module L:SpecSysVar) = (module L : Printable.S) + in + f (D.assoc_dom n) + + let domain_list () = + let f (module L:SpecSysVar) = (module L : Printable.S) in + List.map (fun (x,y) -> (x,f y)) (D.domain_list ()) +end + module DomListPrintable (DLSpec : DomainListPrintableSpec) : Printable.S with type t = (int * unknown) list = @@ -245,81 +257,21 @@ struct QCheck.oneof arbs end -(* TODO: deduplicate *) -module DomVariantPrintableW (DLSpec : DomainListPrintableWSpec) +module DomVariantSysVar (DLSpec : DomainListSysVarSpec) : SpecSysVar with type t = int * unknown = struct - include Printable.Std (* for default invariant, tag, ... *) - open DLSpec - open List open Obj - type t = int * unknown + include DomVariantPrintable (PrintableOfSysVarSpec (DLSpec)) let unop_map f ((n, d):t) = f n (assoc_dom n) d - let pretty () = unop_map (fun n (module S: SpecSysVar) x -> - Pretty.dprintf "%s:%a" (S.name ()) S.pretty (obj x) - ) - - let show = unop_map (fun n (module S: SpecSysVar) x -> - let analysis_name = find_spec_name n in - analysis_name ^ ":" ^ S.show (obj x) - ) - let is_write_only = unop_map (fun n (module S: SpecSysVar) x -> S.is_write_only (obj x) ) - - let to_yojson x = - `Assoc [ - unop_map (fun n (module S: SpecSysVar) x -> - let name = find_spec_name n in - (name, S.to_yojson (obj x)) - ) x - ] - - let equal (n1, x1) (n2, x2) = - n1 = n2 && ( - let module S = (val assoc_dom n1) in - S.equal (obj x1) (obj x2) - ) - - let compare (n1, x1) (n2, x2) = - let r = Stdlib.compare n1 n2 in - if r <> 0 then - r - else - let module S = (val assoc_dom n1) in - S.compare (obj x1) (obj x2) - - let hash = unop_map (fun n (module S: SpecSysVar) x -> - Hashtbl.hash (n, S.hash (obj x)) - ) - - let name () = - let domain_name (n, (module S: SpecSysVar)) = - let analysis_name = find_spec_name n in - analysis_name ^ ":" ^ S.name () - in - IO.to_string (List.print ~first:"" ~last:"" ~sep:" | " String.print) (map domain_name @@ domain_list ()) - - let printXml f = unop_map (fun n (module S: SpecSysVar) x -> - BatPrintf.fprintf f "\n" (find_spec_name n); - S.printXml f (obj x); - BatPrintf.fprintf f "\n" - ) - - let invariant c = unop_map (fun n (module S: SpecSysVar) x -> - S.invariant c (obj x) - ) - - let arbitrary () = - let arbs = map (fun (n, (module S: SpecSysVar)) -> QCheck.map ~rev:(fun (_, o) -> obj o) (fun x -> (n, repr x)) @@ S.arbitrary ()) @@ domain_list () in - QCheck.oneof arbs end module DomListLattice (DLSpec : DomainListLatticeSpec) @@ -422,7 +374,7 @@ struct let domain_list () = List.map (fun (n,p) -> n, p.cont) !activated_ctx_sens end -module VarListSpec : DomainListPrintableWSpec = +module VarListSpec : DomainListSysVarSpec = struct let assoc_dom n = (find_spec n).var let domain_list () = List.map (fun (n,p) -> n, p.var) !activated From 61b965487c98de4fb7b60d674d894384561988b6 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 10 Mar 2022 14:47:19 +0200 Subject: [PATCH 271/402] Extract IncrWrite postsolver in TD3 --- src/solvers/postSolver.ml | 31 +++++++++++++++---------------- src/solvers/td3.ml | 35 ++++++++++++++++++++++++++--------- 2 files changed, 41 insertions(+), 25 deletions(-) diff --git a/src/solvers/postSolver.ml b/src/solvers/postSolver.ml index db6f074174..27b230e9c0 100644 --- a/src/solvers/postSolver.ml +++ b/src/solvers/postSolver.ml @@ -9,8 +9,8 @@ sig module VH: Hashtbl.S with type key = S.v val init: unit -> unit - val one_side: vh:S.Dom.t VH.t -> vhw:S.Dom.t VH.t VH.t -> x:S.v -> y:S.v -> d:S.Dom.t -> unit - val one_constraint: vh:S.Dom.t VH.t -> vhw:S.Dom.t VH.t VH.t -> x:S.v -> rhs:S.Dom.t -> unit + val one_side: vh:S.Dom.t VH.t -> x:S.v -> y:S.v -> d:S.Dom.t -> unit + val one_constraint: vh:S.Dom.t VH.t -> x:S.v -> rhs:S.Dom.t -> unit val finalize: vh:S.Dom.t VH.t -> reachable:unit VH.t -> unit end @@ -26,8 +26,8 @@ module Unit: F = module S = S module VH = VH let init () = () - let one_side ~vh ~vhw ~x ~y ~d = () - let one_constraint ~vh ~vhw ~x ~rhs = () + let one_side ~vh ~x ~y ~d = () + let one_constraint ~vh ~x ~rhs = () let finalize ~vh ~reachable = () end @@ -40,12 +40,12 @@ struct let init () = PS1.init (); PS2.init () - let one_side ~vh ~vhw ~x ~y ~d = - PS1.one_side ~vh ~vhw ~x ~y ~d; - PS2.one_side ~vh ~vhw ~x ~y ~d - let one_constraint ~vh ~vhw ~x ~rhs = - PS1.one_constraint ~vh ~vhw ~x ~rhs; - PS2.one_constraint ~vh ~vhw ~x ~rhs + let one_side ~vh ~x ~y ~d = + PS1.one_side ~vh ~x ~y ~d; + PS2.one_side ~vh ~x ~y ~d + let one_constraint ~vh ~x ~rhs = + PS1.one_constraint ~vh ~x ~rhs; + PS2.one_constraint ~vh ~x ~rhs let finalize ~vh ~reachable = PS1.finalize ~vh ~reachable; PS2.finalize ~vh ~reachable @@ -83,17 +83,16 @@ module Verify: F = Goblintutil.verified := Some false; ignore (Pretty.printf "Fixpoint not reached at %a\nOrigin: %a\n @[Solver computed:\n%a\nSide-effect:\n%a\nDifference: %a\n@]" S.Var.pretty_trace y S.Var.pretty_trace x S.Dom.pretty lhs S.Dom.pretty rhs S.Dom.pretty_diff (rhs, lhs)) - let one_side ~vh ~vhw ~x ~y ~d = + let one_side ~vh ~x ~y ~d = let y_lhs = try VH.find vh y with Not_found -> S.Dom.bot () in if S.Var.is_write_only y then ( (* HACK: incremental accesses etc insanity! *) - VH.replace vh y (S.Dom.join y_lhs d); - VH.modify_def (VH.create 1) x (fun w -> VH.add w y d; w) vhw (* inner add intentional *) + VH.replace vh y (S.Dom.join y_lhs d) ) else if not (S.Dom.leq d y_lhs) then complain_side x y ~lhs:y_lhs ~rhs:d - let one_constraint ~vh ~vhw ~x ~rhs = + let one_constraint ~vh ~x ~rhs = let lhs = try VH.find vh x with Not_found -> S.Dom.bot () in if not (S.Dom.leq rhs lhs) then complain_constraint x ~lhs ~rhs @@ -203,12 +202,12 @@ struct try VH.find vh y with Not_found -> S.Dom.bot () in let set y d = - PS.one_side ~vh ~vhw ~x ~y ~d; + PS.one_side ~vh ~x ~y ~d; (* check before recursing *) one_var y in let rhs = f get set in - PS.one_constraint ~vh ~vhw ~x ~rhs + PS.one_constraint ~vh ~x ~rhs in List.iter one_var vs; diff --git a/src/solvers/td3.ml b/src/solvers/td3.ml index adc5016fc8..c96e04d38b 100644 --- a/src/solvers/td3.ml +++ b/src/solvers/td3.ml @@ -958,7 +958,7 @@ module WP = struct include PostSolver.Unit (S) (HM) - let one_side ~vh ~vhw ~x ~y ~d = + let one_side ~vh ~x ~y ~d = HM.replace side_dep y (VS.add x (try HM.find side_dep y with Not_found -> VS.empty)); HM.replace side_infl x (VS.add y (try HM.find side_infl x with Not_found -> VS.empty)); end @@ -992,13 +992,6 @@ module WP = HM.iter (fun _ m -> Messages.add m ) var_messages; - (* retrigger *) - HM.iter (fun x w -> - HM.iter (fun y d -> - let old_d = try HM.find rho y with Not_found -> S.Dom.bot () in - HM.replace rho y (S.Dom.join old_d d) - ) w - ) rho_write ); (* hook to collect new messages *) @@ -1009,6 +1002,30 @@ module WP = ); end in + + let module IncrWrite: PostSolver.S with module S = S and module VH = HM = + struct + include PostSolver.Unit (S) (HM) + + let init () = + (* retrigger superstable side writes *) + if incr_verify then ( + HM.iter (fun x w -> + HM.iter (fun y d -> + let old_d = try HM.find rho y with Not_found -> S.Dom.bot () in + HM.replace rho y (S.Dom.join old_d d) + ) w + ) rho_write + ) + + let one_side ~vh ~x ~y ~d = + if S.Var.is_write_only y then ( + (* HACK: incremental accesses etc insanity! *) + VH.modify_def (VH.create 1) x (fun w -> VH.add w y d; w) rho_write (* inner add intentional *) + ) + end + in + let module MakeIncrListArg = struct module Arg = @@ -1018,7 +1035,7 @@ module WP = end include PostSolver.ListArgFromStdArg (S) (HM) (Arg) - let postsolvers = (module IncrPrune: M) :: (module SideInfl: M) :: (module IncrWarn: M) :: postsolvers + let postsolvers = (module IncrPrune: M) :: (module SideInfl: M) :: (module IncrWrite: M) :: (module IncrWarn: M) :: postsolvers let init_reachable ~vh = if incr_verify then From 56baff8b3b26f4684bb869f6d9a7855cef68a52e Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 10 Mar 2022 14:51:03 +0200 Subject: [PATCH 272/402] Add incremental pruning of rho_write in TD3 --- src/solvers/td3.ml | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/solvers/td3.ml b/src/solvers/td3.ml index c96e04d38b..5334e68f4b 100644 --- a/src/solvers/td3.ml +++ b/src/solvers/td3.ml @@ -949,6 +949,18 @@ module WP = filter_vs_hm infl; filter_vs_hm side_infl; filter_vs_hm side_dep; + + VH.filteri_inplace (fun x w -> + if VH.mem reachable x then ( + VH.filteri_inplace (fun y _ -> + VH.mem reachable y + ) w; + true + ) + else + false + ) rho_write + (* TODO: prune other data structures? *) end in From 8f394f33129a3e3d45156a48ff4b3ef7854a0844 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 10 Mar 2022 14:57:44 +0200 Subject: [PATCH 273/402] Optimize IncrWrite.one_side --- src/solvers/td3.ml | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/solvers/td3.ml b/src/solvers/td3.ml index 5334e68f4b..04c8aea35a 100644 --- a/src/solvers/td3.ml +++ b/src/solvers/td3.ml @@ -1032,8 +1032,15 @@ module WP = let one_side ~vh ~x ~y ~d = if S.Var.is_write_only y then ( - (* HACK: incremental accesses etc insanity! *) - VH.modify_def (VH.create 1) x (fun w -> VH.add w y d; w) rho_write (* inner add intentional *) + let w = + try + VH.find rho_write x + with Not_found -> + let w = VH.create 1 in (* only create on demand, modify_def would eagerly allocate *) + VH.replace rho_write x w; + w + in + VH.add w y d (* intentional add *) ) end in From e87a91b561143f3c19eb2fc1b6a4a81d4cb14252 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 10 Mar 2022 14:58:53 +0200 Subject: [PATCH 274/402] Remove now-unused rho_write argument from postsolver --- src/framework/constraints.ml | 2 +- src/solvers/postSolver.ml | 6 +++--- src/solvers/td3.ml | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/framework/constraints.ml b/src/framework/constraints.ml index d6f6a0d37b..bdf5722faf 100644 --- a/src/framework/constraints.ml +++ b/src/framework/constraints.ml @@ -803,7 +803,7 @@ module EqIncrSolverFromEqSolver (Sol: GenericEqBoxSolver): GenericEqBoxIncrSolve let solve box xs vs = let vh = Sol.solve box xs vs in - Post.post xs vs vh (VH.create 0); + Post.post xs vs vh; (vh, ()) end diff --git a/src/solvers/postSolver.ml b/src/solvers/postSolver.ml index 27b230e9c0..95e5bf968b 100644 --- a/src/solvers/postSolver.ml +++ b/src/solvers/postSolver.ml @@ -175,7 +175,7 @@ struct module S = PS.S module VH = PS.VH - let post xs vs vh vhw = + let post xs vs vh = if get_bool "dbg.verbose" then print_endline "Postsolving\n"; @@ -254,7 +254,7 @@ struct in Some (List.reduce compose postsolvers) - let post xs vs vh vhw = + let post xs vs vh = match postsolver_opt with | None -> () | Some (module PS) -> @@ -265,7 +265,7 @@ struct end in let module M = MakeIncr (IncrPS) in - M.post xs vs vh vhw + M.post xs vs vh end (** Make complete (non-incremental) postsolving function from list of postsolvers. diff --git a/src/solvers/td3.ml b/src/solvers/td3.ml index 04c8aea35a..abb991dbab 100644 --- a/src/solvers/td3.ml +++ b/src/solvers/td3.ml @@ -1066,7 +1066,7 @@ module WP = let module Post = PostSolver.MakeIncrList (MakeIncrListArg) in - Post.post st vs rho rho_write; + Post.post st vs rho; print_data data "Data after postsolve"; From df2e20551b379cf175ea73c73bfce01bd457849e Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 10 Mar 2022 15:00:16 +0200 Subject: [PATCH 275/402] Update Verify postsolver comment about hack --- src/solvers/postSolver.ml | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/solvers/postSolver.ml b/src/solvers/postSolver.ml index 95e5bf968b..f664cd2589 100644 --- a/src/solvers/postSolver.ml +++ b/src/solvers/postSolver.ml @@ -85,10 +85,8 @@ module Verify: F = let one_side ~vh ~x ~y ~d = let y_lhs = try VH.find vh y with Not_found -> S.Dom.bot () in - if S.Var.is_write_only y then ( - (* HACK: incremental accesses etc insanity! *) - VH.replace vh y (S.Dom.join y_lhs d) - ) + if S.Var.is_write_only y then + VH.replace vh y (S.Dom.join y_lhs d) (* HACK: allow warnings/accesses to be added without complaining *) else if not (S.Dom.leq d y_lhs) then complain_side x y ~lhs:y_lhs ~rhs:d From 3ea3f9e32481b62bca6343cb88d9858fd2cb76ad Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 10 Mar 2022 15:04:01 +0200 Subject: [PATCH 276/402] Prevent unnecessary write-only side restarting --- src/solvers/td3.ml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/solvers/td3.ml b/src/solvers/td3.ml index abb991dbab..3848c0dd0c 100644 --- a/src/solvers/td3.ml +++ b/src/solvers/td3.ml @@ -553,7 +553,7 @@ module WP = let w = HM.find_default side_dep x VS.empty in HM.remove side_dep x; - if not (VS.is_empty w) && (not restart_only_globals || Node.equal (S.Var.node x) (Function Cil.dummyFunDec)) then ( + if not (VS.is_empty w) && (not restart_only_globals || Node.equal (S.Var.node x) (Function Cil.dummyFunDec)) && not (S.Var.is_write_only x) then ( (* restart side-effected var *) restart_leaf x; From b98ee7f6170635d743835176f18faabb02c98a1c Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 10 Mar 2022 15:07:34 +0200 Subject: [PATCH 277/402] Fix SolverTest compilation --- unittest/solver/solverTest.ml | 1 + 1 file changed, 1 insertion(+) diff --git a/unittest/solver/solverTest.ml b/unittest/solver/solverTest.ml index 7d8cd41858..1751ffcee2 100644 --- a/unittest/solver/solverTest.ml +++ b/unittest/solver/solverTest.ml @@ -16,6 +16,7 @@ struct let line_nr _ = 1 let node _ = failwith "no node" let relift x = x + let is_write_only _ = false end (* domain is (reversed) integers *) From 44d206ab871a32d2d1e288f3f9b13ed4c1733882 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 10 Mar 2022 15:11:48 +0200 Subject: [PATCH 278/402] Add incremental test with access through wrapper function --- .../11-restart/13-mutex-simple-wrap.c | 27 +++++++++++++++++++ .../11-restart/13-mutex-simple-wrap.json | 9 +++++++ .../11-restart/13-mutex-simple-wrap.patch | 22 +++++++++++++++ 3 files changed, 58 insertions(+) create mode 100644 tests/incremental/11-restart/13-mutex-simple-wrap.c create mode 100644 tests/incremental/11-restart/13-mutex-simple-wrap.json create mode 100644 tests/incremental/11-restart/13-mutex-simple-wrap.patch diff --git a/tests/incremental/11-restart/13-mutex-simple-wrap.c b/tests/incremental/11-restart/13-mutex-simple-wrap.c new file mode 100644 index 0000000000..53ff298524 --- /dev/null +++ b/tests/incremental/11-restart/13-mutex-simple-wrap.c @@ -0,0 +1,27 @@ +#include +#include + +int myglobal; +pthread_mutex_t mutex1 = PTHREAD_MUTEX_INITIALIZER; +pthread_mutex_t mutex2 = PTHREAD_MUTEX_INITIALIZER; + +void *t_fun(void *arg) { + pthread_mutex_lock(&mutex1); + myglobal=myglobal+1; // RACE! + pthread_mutex_unlock(&mutex1); + return NULL; +} + +void wrap() { + pthread_mutex_lock(&mutex2); + myglobal=myglobal+1; // RACE! + pthread_mutex_unlock(&mutex2); +} + +int main(void) { + pthread_t id; + pthread_create(&id, NULL, t_fun, NULL); + wrap(); + pthread_join (id, NULL); + return 0; +} diff --git a/tests/incremental/11-restart/13-mutex-simple-wrap.json b/tests/incremental/11-restart/13-mutex-simple-wrap.json new file mode 100644 index 0000000000..daff0678ce --- /dev/null +++ b/tests/incremental/11-restart/13-mutex-simple-wrap.json @@ -0,0 +1,9 @@ +{ + "incremental": { + "restart": { + "sided": { + "enabled": false + } + } + } +} \ No newline at end of file diff --git a/tests/incremental/11-restart/13-mutex-simple-wrap.patch b/tests/incremental/11-restart/13-mutex-simple-wrap.patch new file mode 100644 index 0000000000..89e713a9c3 --- /dev/null +++ b/tests/incremental/11-restart/13-mutex-simple-wrap.patch @@ -0,0 +1,22 @@ +--- tests/incremental/11-restart/13-mutex-simple-wrap.c ++++ tests/incremental/11-restart/13-mutex-simple-wrap.c +@@ -7,15 +7,15 @@ pthread_mutex_t mutex2 = PTHREAD_MUTEX_INITIALIZER; + + void *t_fun(void *arg) { + pthread_mutex_lock(&mutex1); +- myglobal=myglobal+1; // RACE! ++ myglobal=myglobal+1; // NORACE + pthread_mutex_unlock(&mutex1); + return NULL; + } + + void wrap() { +- pthread_mutex_lock(&mutex2); +- myglobal=myglobal+1; // RACE! +- pthread_mutex_unlock(&mutex2); ++ pthread_mutex_lock(&mutex1); ++ myglobal=myglobal+1; // NORACE ++ pthread_mutex_unlock(&mutex1); + } + + int main(void) { From e86b9da21494cf704a76ef86c7661951151a5f90 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 10 Mar 2022 15:13:38 +0200 Subject: [PATCH 279/402] Move write-only sided restart incremental tests to 13-restart-write --- .../12-mutex-simple.c => 13-restart-write/01-mutex-simple.c} | 0 .../01-mutex-simple.json} | 0 .../01-mutex-simple.patch} | 4 ++-- .../02-mutex-simple-wrap.c} | 0 .../02-mutex-simple-wrap.json} | 0 .../02-mutex-simple-wrap.patch} | 4 ++-- 6 files changed, 4 insertions(+), 4 deletions(-) rename tests/incremental/{11-restart/12-mutex-simple.c => 13-restart-write/01-mutex-simple.c} (100%) rename tests/incremental/{11-restart/12-mutex-simple.json => 13-restart-write/01-mutex-simple.json} (100%) rename tests/incremental/{11-restart/12-mutex-simple.patch => 13-restart-write/01-mutex-simple.patch} (84%) rename tests/incremental/{11-restart/13-mutex-simple-wrap.c => 13-restart-write/02-mutex-simple-wrap.c} (100%) rename tests/incremental/{11-restart/13-mutex-simple-wrap.json => 13-restart-write/02-mutex-simple-wrap.json} (100%) rename tests/incremental/{11-restart/13-mutex-simple-wrap.patch => 13-restart-write/02-mutex-simple-wrap.patch} (79%) diff --git a/tests/incremental/11-restart/12-mutex-simple.c b/tests/incremental/13-restart-write/01-mutex-simple.c similarity index 100% rename from tests/incremental/11-restart/12-mutex-simple.c rename to tests/incremental/13-restart-write/01-mutex-simple.c diff --git a/tests/incremental/11-restart/12-mutex-simple.json b/tests/incremental/13-restart-write/01-mutex-simple.json similarity index 100% rename from tests/incremental/11-restart/12-mutex-simple.json rename to tests/incremental/13-restart-write/01-mutex-simple.json diff --git a/tests/incremental/11-restart/12-mutex-simple.patch b/tests/incremental/13-restart-write/01-mutex-simple.patch similarity index 84% rename from tests/incremental/11-restart/12-mutex-simple.patch rename to tests/incremental/13-restart-write/01-mutex-simple.patch index 14913c581d..156312b915 100644 --- a/tests/incremental/11-restart/12-mutex-simple.patch +++ b/tests/incremental/13-restart-write/01-mutex-simple.patch @@ -1,5 +1,5 @@ ---- tests/incremental/11-restart/12-mutex-simple.c -+++ tests/incremental/11-restart/12-mutex-simple.c +--- tests/incremental/13-restart-write/01-mutex-simple.c ++++ tests/incremental/13-restart-write/01-mutex-simple.c @@ -7,7 +7,7 @@ pthread_mutex_t mutex2 = PTHREAD_MUTEX_INITIALIZER; void *t_fun(void *arg) { diff --git a/tests/incremental/11-restart/13-mutex-simple-wrap.c b/tests/incremental/13-restart-write/02-mutex-simple-wrap.c similarity index 100% rename from tests/incremental/11-restart/13-mutex-simple-wrap.c rename to tests/incremental/13-restart-write/02-mutex-simple-wrap.c diff --git a/tests/incremental/11-restart/13-mutex-simple-wrap.json b/tests/incremental/13-restart-write/02-mutex-simple-wrap.json similarity index 100% rename from tests/incremental/11-restart/13-mutex-simple-wrap.json rename to tests/incremental/13-restart-write/02-mutex-simple-wrap.json diff --git a/tests/incremental/11-restart/13-mutex-simple-wrap.patch b/tests/incremental/13-restart-write/02-mutex-simple-wrap.patch similarity index 79% rename from tests/incremental/11-restart/13-mutex-simple-wrap.patch rename to tests/incremental/13-restart-write/02-mutex-simple-wrap.patch index 89e713a9c3..e38d432722 100644 --- a/tests/incremental/11-restart/13-mutex-simple-wrap.patch +++ b/tests/incremental/13-restart-write/02-mutex-simple-wrap.patch @@ -1,5 +1,5 @@ ---- tests/incremental/11-restart/13-mutex-simple-wrap.c -+++ tests/incremental/11-restart/13-mutex-simple-wrap.c +--- tests/incremental/13-restart-write/02-mutex-simple-wrap.c ++++ tests/incremental/13-restart-write/02-mutex-simple-wrap.c @@ -7,15 +7,15 @@ pthread_mutex_t mutex2 = PTHREAD_MUTEX_INITIALIZER; void *t_fun(void *arg) { From 1d011ccb3cf77a43d3d95af34d6c7a6d3edc9bb9 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 10 Mar 2022 17:35:57 +0200 Subject: [PATCH 280/402] Add incremental test 13-restart-write/03-mutex-simple-nochange This checks that race warnings don't all disappear. --- .../03-mutex-simple-nochange.c | 23 +++++++++++++++++++ .../03-mutex-simple-nochange.json | 9 ++++++++ .../03-mutex-simple-nochange.patch | 0 3 files changed, 32 insertions(+) create mode 100644 tests/incremental/13-restart-write/03-mutex-simple-nochange.c create mode 100644 tests/incremental/13-restart-write/03-mutex-simple-nochange.json create mode 100644 tests/incremental/13-restart-write/03-mutex-simple-nochange.patch diff --git a/tests/incremental/13-restart-write/03-mutex-simple-nochange.c b/tests/incremental/13-restart-write/03-mutex-simple-nochange.c new file mode 100644 index 0000000000..82c1642a93 --- /dev/null +++ b/tests/incremental/13-restart-write/03-mutex-simple-nochange.c @@ -0,0 +1,23 @@ +#include +#include + +int myglobal; +pthread_mutex_t mutex1 = PTHREAD_MUTEX_INITIALIZER; +pthread_mutex_t mutex2 = PTHREAD_MUTEX_INITIALIZER; + +void *t_fun(void *arg) { + pthread_mutex_lock(&mutex1); + myglobal=myglobal+1; // RACE! + pthread_mutex_unlock(&mutex1); + return NULL; +} + +int main(void) { + pthread_t id; + pthread_create(&id, NULL, t_fun, NULL); + pthread_mutex_lock(&mutex2); + myglobal=myglobal+1; // RACE! + pthread_mutex_unlock(&mutex2); + pthread_join (id, NULL); + return 0; +} diff --git a/tests/incremental/13-restart-write/03-mutex-simple-nochange.json b/tests/incremental/13-restart-write/03-mutex-simple-nochange.json new file mode 100644 index 0000000000..daff0678ce --- /dev/null +++ b/tests/incremental/13-restart-write/03-mutex-simple-nochange.json @@ -0,0 +1,9 @@ +{ + "incremental": { + "restart": { + "sided": { + "enabled": false + } + } + } +} \ No newline at end of file diff --git a/tests/incremental/13-restart-write/03-mutex-simple-nochange.patch b/tests/incremental/13-restart-write/03-mutex-simple-nochange.patch new file mode 100644 index 0000000000..e69de29bb2 From 1aafc7798447401b2a8cd5b2c5ddccd4d5e2027a Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 10 Mar 2022 17:30:14 +0200 Subject: [PATCH 281/402] Update commented-out debug prints for write-only incremental restarting --- src/framework/control.ml | 2 +- src/solvers/td3.ml | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/framework/control.ml b/src/framework/control.ml index e55dcb018f..e3676e5477 100644 --- a/src/framework/control.ml +++ b/src/framework/control.ml @@ -598,7 +598,7 @@ struct CfgTools.dead_code_cfg file (module Cfg : CfgBidir) liveness; let warn_global g v = - (* ignore (Pretty.printf "warn_global %a %a\n" CilType.Varinfo.pretty g EQSys.G.pretty v); *) + (* ignore (Pretty.printf "warn_global %a %a\n" EQSys.GVar.pretty_trace g EQSys.G.pretty v); *) (* build a ctx for using the query system *) let rec ctx = { ask = (fun (type a) (q: a Queries.t) -> Spec.query ctx q) diff --git a/src/solvers/td3.ml b/src/solvers/td3.ml index 3848c0dd0c..f1f5714291 100644 --- a/src/solvers/td3.ml +++ b/src/solvers/td3.ml @@ -1025,6 +1025,7 @@ module WP = HM.iter (fun x w -> HM.iter (fun y d -> let old_d = try HM.find rho y with Not_found -> S.Dom.bot () in + (* ignore (Pretty.printf "rho_write retrigger %a %a %a %a\n" S.Var.pretty_trace x S.Var.pretty_trace y S.Dom.pretty old_d S.Dom.pretty d); *) HM.replace rho y (S.Dom.join old_d d) ) w ) rho_write @@ -1032,6 +1033,7 @@ module WP = let one_side ~vh ~x ~y ~d = if S.Var.is_write_only y then ( + (* ignore (Pretty.printf "rho_write collect %a %a %a\n" S.Var.pretty_trace x S.Var.pretty_trace y S.Dom.pretty d); *) let w = try VH.find rho_write x From d224f50e13cecc94eb60500a9ce2e4e119fd88cb Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 10 Mar 2022 17:30:29 +0200 Subject: [PATCH 282/402] Enable allglobs in test-incremental.sh --- scripts/test-incremental.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/test-incremental.sh b/scripts/test-incremental.sh index fa95f25f42..5541afb55d 100755 --- a/scripts/test-incremental.sh +++ b/scripts/test-incremental.sh @@ -11,7 +11,7 @@ source=$base/$test.c conf=$base/$test.json patch=$base/$test.patch -args="--enable dbg.debug --enable printstats -v" +args="--enable dbg.debug --enable printstats -v --enable allglobs" ./goblint --conf $conf $args --enable incremental.save $source &> $base/$test.before.log From faaf8d7f5aa67bdf9c67aef8b1cf4fcfe6c80aa6 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 10 Mar 2022 17:33:34 +0200 Subject: [PATCH 283/402] Fix retriggered superstable write sides not being reachable This caused them to be incorrectly pruned. --- src/solvers/td3.ml | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/solvers/td3.ml b/src/solvers/td3.ml index f1f5714291..9940efc3f8 100644 --- a/src/solvers/td3.ml +++ b/src/solvers/td3.ml @@ -992,6 +992,13 @@ module WP = HM.clear rho_write ); + let init_reachable = + if incr_verify then + HM.copy superstable (* consider superstable reached: stop recursion (evaluation) and keep from being pruned *) + else + HM.create 0 (* doesn't matter, not used *) + in + let module IncrWarn: PostSolver.S with module S = S and module VH = HM = struct include PostSolver.Warn (S) (HM) @@ -1026,7 +1033,8 @@ module WP = HM.iter (fun y d -> let old_d = try HM.find rho y with Not_found -> S.Dom.bot () in (* ignore (Pretty.printf "rho_write retrigger %a %a %a %a\n" S.Var.pretty_trace x S.Var.pretty_trace y S.Dom.pretty old_d S.Dom.pretty d); *) - HM.replace rho y (S.Dom.join old_d d) + HM.replace rho y (S.Dom.join old_d d); + HM.replace init_reachable y (); ) w ) rho_write ) @@ -1060,7 +1068,7 @@ module WP = let init_reachable ~vh = if incr_verify then - HM.copy superstable (* consider superstable reached: stop recursion (evaluation) and keep from being pruned *) + init_reachable else HM.create (HM.length vh) end From 37a330f4def2b2fc67ad6ad31b90c2f3ece94996 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 10 Mar 2022 17:38:31 +0200 Subject: [PATCH 284/402] Add incremental test 11-restart/07-local-wpoint-nochange One read access disappears due to broken rho_write relift. --- .../11-restart/07-local-wpoint-nochange.c | 23 +++++++++++++++++++ .../11-restart/07-local-wpoint-nochange.json | 10 ++++++++ .../11-restart/07-local-wpoint-nochange.patch | 0 3 files changed, 33 insertions(+) create mode 100644 tests/incremental/11-restart/07-local-wpoint-nochange.c create mode 100644 tests/incremental/11-restart/07-local-wpoint-nochange.json create mode 100644 tests/incremental/11-restart/07-local-wpoint-nochange.patch diff --git a/tests/incremental/11-restart/07-local-wpoint-nochange.c b/tests/incremental/11-restart/07-local-wpoint-nochange.c new file mode 100644 index 0000000000..747693452a --- /dev/null +++ b/tests/incremental/11-restart/07-local-wpoint-nochange.c @@ -0,0 +1,23 @@ +#include +#include + +int g = 1; + +void* t_fun(void *arg) { + g = 0; + return NULL; +} + +int main() { + pthread_t id; + pthread_create(&id, NULL, t_fun, NULL); // just go multithreaded + + int x; + x = g; + while (1) { + assert(x == 1); // UNKNOWN before, UNKNOWN after + x = g; + } + + return 0; +} \ No newline at end of file diff --git a/tests/incremental/11-restart/07-local-wpoint-nochange.json b/tests/incremental/11-restart/07-local-wpoint-nochange.json new file mode 100644 index 0000000000..ff773f6993 --- /dev/null +++ b/tests/incremental/11-restart/07-local-wpoint-nochange.json @@ -0,0 +1,10 @@ +{ + "ana": { + "int": { + "interval": true + } + }, + "incremental": { + "wpoint": false + } +} \ No newline at end of file diff --git a/tests/incremental/11-restart/07-local-wpoint-nochange.patch b/tests/incremental/11-restart/07-local-wpoint-nochange.patch new file mode 100644 index 0000000000..e69de29bb2 From 4b23cc72608ab52c552f46ae10ea549e7c482139 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 10 Mar 2022 17:33:55 +0200 Subject: [PATCH 285/402] Fix rho_write relift in TD3 --- src/solvers/td3.ml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/solvers/td3.ml b/src/solvers/td3.ml index 9940efc3f8..d9f7163d34 100644 --- a/src/solvers/td3.ml +++ b/src/solvers/td3.ml @@ -1149,7 +1149,7 @@ module WP = HM.iter (fun x w -> let w' = HM.create (HM.length w) in HM.iter (fun y d -> - HM.replace w' (S.Var.relift y) (S.Dom.relift d) + HM.add w' (S.Var.relift y) (S.Dom.relift d) (* w contains duplicate keys, so must add not replace! *) ) w; HM.replace rho_write' (S.Var.relift x) w'; ) data.rho_write; From 574185faa963d47a826526c61b25558c31cd0f55 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 10 Mar 2022 17:35:15 +0200 Subject: [PATCH 286/402] Add write-only sides to stable --- src/solvers/td3.ml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/solvers/td3.ml b/src/solvers/td3.ml index d9f7163d34..235e0e2b74 100644 --- a/src/solvers/td3.ml +++ b/src/solvers/td3.ml @@ -1035,6 +1035,7 @@ module WP = (* ignore (Pretty.printf "rho_write retrigger %a %a %a %a\n" S.Var.pretty_trace x S.Var.pretty_trace y S.Dom.pretty old_d S.Dom.pretty d); *) HM.replace rho y (S.Dom.join old_d d); HM.replace init_reachable y (); + HM.replace stable y (); (* make stable just in case, so following incremental load would have in superstable *) ) w ) rho_write ) @@ -1042,6 +1043,7 @@ module WP = let one_side ~vh ~x ~y ~d = if S.Var.is_write_only y then ( (* ignore (Pretty.printf "rho_write collect %a %a %a\n" S.Var.pretty_trace x S.Var.pretty_trace y S.Dom.pretty d); *) + HM.replace stable y (); (* make stable just in case, so following incremental load would have in superstable *) let w = try VH.find rho_write x From f98796399d2d55f1a0c500688de99767a8a4f830 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Fri, 11 Mar 2022 13:39:43 +0200 Subject: [PATCH 287/402] Document TD3 IncrWrite postsolver --- src/solvers/td3.ml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/solvers/td3.ml b/src/solvers/td3.ml index 235e0e2b74..868fa0c3cd 100644 --- a/src/solvers/td3.ml +++ b/src/solvers/td3.ml @@ -1022,6 +1022,8 @@ module WP = end in + (** Incremental write-only side effect restart handling: + retriggers superstable ones (after restarting above) and collects new (non-superstable) ones. *) let module IncrWrite: PostSolver.S with module S = S and module VH = HM = struct include PostSolver.Unit (S) (HM) From 2c058b10c0dc3b2df2fb6d0a203c2abca300c794 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Fri, 11 Mar 2022 14:19:47 +0200 Subject: [PATCH 288/402] Fix partitioned array option in additional test --- tests/regression/34-localwn_restart/04-hh.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/regression/34-localwn_restart/04-hh.c b/tests/regression/34-localwn_restart/04-hh.c index 24e82cc105..4f784bac6c 100644 --- a/tests/regression/34-localwn_restart/04-hh.c +++ b/tests/regression/34-localwn_restart/04-hh.c @@ -1,7 +1,7 @@ -// SKIP PARAM: --enable ana.int.interval --set solver td3 --enable ana.base.partition-arrays.enabled --set ana.activated "['base','threadid','threadflag','expRelation','mallocWrapper','apron']" --set ana.base.privatization none --set ana.apron.privatization dummy --set sem.int.signed_overflow assume_none +// SKIP PARAM: --enable ana.int.interval --set solver td3 --set ana.base.arrays.domain partitioned --set ana.activated "['base','threadid','threadflag','expRelation','mallocWrapper','apron']" --set ana.base.privatization none --set ana.apron.privatization dummy --set sem.int.signed_overflow assume_none // This is part of 34-localization, but also symlinked to 36-apron. -// ALSO: --enable ana.int.interval --set solver slr3 --enable ana.base.partition-arrays.enabled --set ana.activated "['base','threadid','threadflag','expRelation','mallocWrapper','apron']" --set ana.base.privatization none --set ana.apron.privatization dummy --set sem.int.signed_overflow assume_none +// ALSO: --enable ana.int.interval --set solver slr3 --set ana.base.arrays.domain partitioned --set ana.activated "['base','threadid','threadflag','expRelation','mallocWrapper','apron']" --set ana.base.privatization none --set ana.apron.privatization dummy --set sem.int.signed_overflow assume_none // Example from Halbwachs-Henry, SAS 2012 // Localized widening or restart policy should be able to prove that i <= j+3 // if the abstract domain is powerful enough. From aacdaab233019ac6e77937752703ef793bb0b117 Mon Sep 17 00:00:00 2001 From: stilscher <66023521+stilscher@users.noreply.github.com> Date: Mon, 7 Mar 2022 13:09:35 +0100 Subject: [PATCH 289/402] exclude functions with changed header from reluctant destabilization --- src/incremental/compareCIL.ml | 43 +++++++++++++++++++---------------- src/solvers/td3.ml | 2 +- src/util/server.ml | 4 ++-- 3 files changed, 27 insertions(+), 22 deletions(-) diff --git a/src/incremental/compareCIL.ml b/src/incremental/compareCIL.ml index 1f6bfffa4b..45acb509c3 100644 --- a/src/incremental/compareCIL.ml +++ b/src/incremental/compareCIL.ml @@ -23,15 +23,17 @@ type change_info = { mutable unchanged: global list; mutable removed: global list; mutable added: global list; - mutable force_reanalyze: VarinfoSet.t; + mutable exclude_from_rel_destab: VarinfoSet.t; (** Set of functions that are to be force-reanalyzed. These functions are additionally included in the [changed] field, among the other changed globals. *) } let empty_change_info () : change_info = - {added = []; removed = []; changed = []; unchanged = []; force_reanalyze = VarinfoSet.empty} + {added = []; removed = []; changed = []; unchanged = []; exclude_from_rel_destab = VarinfoSet.empty} -type change_status = Unchanged | Changed | ForceReanalyze of Cil.fundec +(* 'ChangedFunHeader' is used for functions whose varinfo or formal parameters changed. 'Changed' is used only for + * changed functions whose header is unchanged and changed non-function globals *) +type change_status = Unchanged | Changed | ChangedFunHeader of Cil.fundec | ForceReanalyze of Cil.fundec (** Given a boolean that indicates whether the code object is identical to the previous version, returns the corresponding [change_status]*) let unchanged_to_change_status = function @@ -45,13 +47,14 @@ let should_reanalyze (fdec: Cil.fundec) = * nodes of the function changed. If on the other hand no CFGs are provided, the "old" AST comparison on the CIL.file is * used for functions. Then no information is collected regarding which parts/nodes of the function changed. *) let eqF (old: Cil.fundec) (current: Cil.fundec) (cfgs : (cfg * cfg) option) = - let unchangedHeader = eq_varinfo old.svar current.svar && GobList.equal eq_varinfo old.sformals current.sformals in - let change_status, diffOpt = - if should_reanalyze current then - ForceReanalyze current, None + if should_reanalyze current then + ForceReanalyze current, None + else + let unchangedHeader = eq_varinfo old.svar current.svar && GobList.equal eq_varinfo old.sformals current.sformals in + if not unchangedHeader then ChangedFunHeader current, None else - let sameDef = unchangedHeader && GobList.equal eq_varinfo old.slocals current.slocals in - if not sameDef then + let sameLocals = GobList.equal eq_varinfo old.slocals current.slocals in + if not sameLocals then (Changed, None) else match cfgs with @@ -62,14 +65,12 @@ let eqF (old: Cil.fundec) (current: Cil.fundec) (cfgs : (cfg * cfg) option) = let matches, diffNodes1, diffNodes2 = compareFun (module CfgOld) (module CfgNew) old current in if diffNodes1 = [] && diffNodes2 = [] then (Changed, None) else (Changed, Some {unchangedNodes = matches; primObsoleteNodes = diffNodes1; primNewNodes = diffNodes2}) - in - change_status, unchangedHeader, diffOpt let eq_glob (old: global) (current: global) (cfgs : (cfg * cfg) option) = match old, current with | GFun (f,_), GFun (g,_) -> eqF f g cfgs - | GVar (x, init_x, _), GVar (y, init_y, _) -> unchanged_to_change_status (eq_varinfo x y), false, None (* ignore the init_info - a changed init of a global will lead to a different start state *) - | GVarDecl (x, _), GVarDecl (y, _) -> unchanged_to_change_status (eq_varinfo x y), false, None - | _ -> ignore @@ Pretty.printf "Not comparable: %a and %a\n" Cil.d_global old Cil.d_global current; Changed, false, None + | GVar (x, init_x, _), GVar (y, init_y, _) -> unchanged_to_change_status (eq_varinfo x y), None (* ignore the init_info - a changed init of a global will lead to a different start state *) + | GVarDecl (x, _), GVarDecl (y, _) -> unchanged_to_change_status (eq_varinfo x y), None + | _ -> ignore @@ Pretty.printf "Not comparable: %a and %a\n" Cil.d_global old Cil.d_global current; Changed, None let compareCilFiles ?(eq=eq_glob) (oldAST: file) (newAST: file) = let cfgs = if GobConfig.get_string "incremental.compare" = "cfg" @@ -94,16 +95,20 @@ let compareCilFiles ?(eq=eq_glob) (oldAST: file) (newAST: file) = let ident = identifier_of_global global in let old_global = GlobalMap.find ident map in (* Do a (recursive) equal comparison ignoring location information *) - let change_status, unchangedHeader, diff = eq old_global global cfgs in - let append_to_changed () = + let change_status, diff = eq old_global global cfgs in + let append_to_changed (unchangedHeader) = changes.changed <- {current = global; old = old_global; unchangedHeader; diff} :: changes.changed in match change_status with - | Changed -> append_to_changed () + | ChangedFunHeader f -> + changes.exclude_from_rel_destab <- VarinfoSet.add f.svar changes.exclude_from_rel_destab; + append_to_changed false + | Changed -> + append_to_changed true | Unchanged -> changes.unchanged <- global :: changes.unchanged | ForceReanalyze f -> - changes.force_reanalyze <- VarinfoSet.add f.svar changes.force_reanalyze; - append_to_changed () + changes.exclude_from_rel_destab <- VarinfoSet.add f.svar changes.exclude_from_rel_destab; + append_to_changed false; with Not_found -> () (* Global was no variable or function, it does not belong into the map *) in let checkExists map global = diff --git a/src/solvers/td3.ml b/src/solvers/td3.ml index 868fa0c3cd..13e3753978 100644 --- a/src/solvers/td3.ml +++ b/src/solvers/td3.ml @@ -634,7 +634,7 @@ module WP = let reanalyze_entry f = (* destabilize the entry points of a changed function when reluctant is off, or the function is to be force-reanalyzed *) - (not reluctant) || CompareCIL.VarinfoSet.mem f.svar S.increment.changes.force_reanalyze + (not reluctant) || CompareCIL.VarinfoSet.mem f.svar S.increment.changes.exclude_from_rel_destab in let obsolete_ret = HM.create 103 in let obsolete_entry = HM.create 103 in diff --git a/src/util/server.ml b/src/util/server.ml index 66a61a7f92..34c494d5ac 100644 --- a/src/util/server.ml +++ b/src/util/server.ml @@ -132,8 +132,8 @@ let reparse (s: t) = (* Only called when the file has not been reparsed, so we can skip the expensive CFG comparison. *) let virtual_changes file = let eq (glob: Cil.global) _ _ = match glob with - | GFun (fdec, _) when CompareCIL.should_reanalyze fdec -> CompareCIL.ForceReanalyze fdec, false, None - | _ -> Unchanged, false, None + | GFun (fdec, _) when CompareCIL.should_reanalyze fdec -> CompareCIL.ForceReanalyze fdec, None + | _ -> Unchanged, None in CompareCIL.compareCilFiles ~eq file file From 3d23659575410b9f94cf3d1afb94b9900123d2e0 Mon Sep 17 00:00:00 2001 From: stilscher <66023521+stilscher@users.noreply.github.com> Date: Wed, 30 Mar 2022 18:25:53 +0200 Subject: [PATCH 290/402] named parameter for unchangedHeader --- src/incremental/compareCIL.ml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/incremental/compareCIL.ml b/src/incremental/compareCIL.ml index 45acb509c3..843542dbd1 100644 --- a/src/incremental/compareCIL.ml +++ b/src/incremental/compareCIL.ml @@ -96,19 +96,19 @@ let compareCilFiles ?(eq=eq_glob) (oldAST: file) (newAST: file) = let old_global = GlobalMap.find ident map in (* Do a (recursive) equal comparison ignoring location information *) let change_status, diff = eq old_global global cfgs in - let append_to_changed (unchangedHeader) = + let append_to_changed ~unchangedHeader = changes.changed <- {current = global; old = old_global; unchangedHeader; diff} :: changes.changed in match change_status with | ChangedFunHeader f -> changes.exclude_from_rel_destab <- VarinfoSet.add f.svar changes.exclude_from_rel_destab; - append_to_changed false + append_to_changed ~unchangedHeader:false | Changed -> - append_to_changed true + append_to_changed ~unchangedHeader:true | Unchanged -> changes.unchanged <- global :: changes.unchanged | ForceReanalyze f -> changes.exclude_from_rel_destab <- VarinfoSet.add f.svar changes.exclude_from_rel_destab; - append_to_changed false; + append_to_changed ~unchangedHeader:false; with Not_found -> () (* Global was no variable or function, it does not belong into the map *) in let checkExists map global = From 140769b66d24791376e57ac2e93655d2faf167c1 Mon Sep 17 00:00:00 2001 From: stilscher <66023521+stilscher@users.noreply.github.com> Date: Wed, 30 Mar 2022 18:49:14 +0200 Subject: [PATCH 291/402] remove duplicate code --- src/incremental/compareCIL.ml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/incremental/compareCIL.ml b/src/incremental/compareCIL.ml index 843542dbd1..341f271a30 100644 --- a/src/incremental/compareCIL.ml +++ b/src/incremental/compareCIL.ml @@ -100,12 +100,10 @@ let compareCilFiles ?(eq=eq_glob) (oldAST: file) (newAST: file) = changes.changed <- {current = global; old = old_global; unchangedHeader; diff} :: changes.changed in match change_status with - | ChangedFunHeader f -> - changes.exclude_from_rel_destab <- VarinfoSet.add f.svar changes.exclude_from_rel_destab; - append_to_changed ~unchangedHeader:false | Changed -> append_to_changed ~unchangedHeader:true | Unchanged -> changes.unchanged <- global :: changes.unchanged + | ChangedFunHeader f | ForceReanalyze f -> changes.exclude_from_rel_destab <- VarinfoSet.add f.svar changes.exclude_from_rel_destab; append_to_changed ~unchangedHeader:false; From d1e5423780eef2fe85f040feafde136cac160dfe Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Mon, 4 Apr 2022 12:19:20 +0300 Subject: [PATCH 292/402] Fix missed solverdiffs renames during merge See https://github.com/goblint/analyzer/commit/d3ef557be82e40740eae2b43e0e8329ef2a59aad#r70387787. --- src/framework/constraints.ml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/framework/constraints.ml b/src/framework/constraints.ml index 5cd050c521..cf85bcb73c 100644 --- a/src/framework/constraints.ml +++ b/src/framework/constraints.ml @@ -1244,7 +1244,7 @@ struct ignore (Pretty.printf "Global %a is more precise using right:\n%a\n" Sys.GVar.pretty_trace k G.pretty_diff (v1,v2)); f_gr () end else begin - if get_bool "solverdiffs" then ( + if get_bool "dbg.compare_runs.diff" then ( ignore (Pretty.printf "Global %a is incomparable (diff):\n%a\n" Sys.GVar.pretty_trace k G.pretty_diff (v1,v2)); ignore (Pretty.printf "Global %a is incomparable (reverse diff):\n%a\n" Sys.GVar.pretty_trace k G.pretty_diff (v2,v1)); ); @@ -1272,7 +1272,7 @@ struct ignore (Pretty.printf "%a @@ %a is more precise using right:\n%a\n" Node.pretty_plain k CilType.Location.pretty (Node.location k) D.pretty_diff (v1,v2)); incr gr end else begin - if get_bool "solverdiffs" then ( + if get_bool "dbg.compare_runs.diff" then ( ignore (Pretty.printf "%a @@ %a is incomparable (diff):\n%a\n" Node.pretty_plain k CilType.Location.pretty (Node.location k) D.pretty_diff (v1,v2)); ignore (Pretty.printf "%a @@ %a is incomparable (reverse diff):\n%a\n" Node.pretty_plain k CilType.Location.pretty (Node.location k) D.pretty_diff (v2,v1)); ); @@ -1309,7 +1309,7 @@ struct ignore (Pretty.printf "%a is more precise using right:\n%a\n" Sys.LVar.pretty_trace k D.pretty_diff (v1,v2)); f_gr () end else begin - if get_bool "solverdiffs" then ( + if get_bool "dbg.compare_runs.diff" then ( ignore (Pretty.printf "%a is incomparable (diff):\n%a\n" Sys.LVar.pretty_trace k D.pretty_diff (v1,v2)); ignore (Pretty.printf "%a is incomparable (reverse diff):\n%a\n" Sys.LVar.pretty_trace k D.pretty_diff (v2,v1)); ); From c839866ab39e0595c08ad310814c953600ef53f2 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Mon, 4 Apr 2022 15:53:48 +0300 Subject: [PATCH 293/402] Disable interactive sided and wpoint restart by default --- src/util/options.schema.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/util/options.schema.json b/src/util/options.schema.json index d8d1185710..f6cbe4a032 100644 --- a/src/util/options.schema.json +++ b/src/util/options.schema.json @@ -977,7 +977,7 @@ "title": "incremental.restart.sided.enabled", "description": "TODO", "type": "boolean", - "default": true + "default": false }, "only-global": { "title": "incremental.restart.sided.only-global", @@ -1805,7 +1805,7 @@ "title": "solvers.td3.restart.wpoint.enabled", "description": "TODO", "type": "boolean", - "default": true + "default": false }, "once": { "title": "solvers.td3.restart.wpoint.once", From b516cd43b6f8d0292f92bacb6503987ff6b040e9 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Tue, 5 Apr 2022 16:16:22 +0300 Subject: [PATCH 294/402] Fix TD3 incremental warning not removing hook --- src/solvers/td3.ml | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/solvers/td3.ml b/src/solvers/td3.ml index 3f714c15b4..1b52aa81c5 100644 --- a/src/solvers/td3.ml +++ b/src/solvers/td3.ml @@ -1033,7 +1033,13 @@ module WP = match !current_var with | Some x -> HM.add var_messages x m | None -> () - ); + ) + + let finalize ~vh ~reachable = + finalize ~vh ~reachable; (* disable warning like standard Warn *) + + (* unhook to avoid accidental var_messages modifications *) + Messages.Table.add_hook := (fun _ -> ()) end in From 2841d76e4808ecfca48a3214b7fcbfd4310b6c57 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Tue, 5 Apr 2022 16:25:10 +0300 Subject: [PATCH 295/402] Update incremental restarting test confs --- .../00-basic/03-changed_start_state2.json | 7 +++++++ .../00-basic/03-changed_start_state2.patch | 4 ++-- .../11-restart/02-global-remove.json | 10 ++++++++-- .../11-restart/03-global-change.json | 7 +++++++ .../11-restart/05-local-wpoint.json | 16 +++++++++++++++- .../11-restart/06-local-wpoint-read.json | 18 ++++++++++++++++-- .../incremental/11-restart/09-call-remove.json | 10 ++++++++-- .../11-restart/11-paper-example.json | 9 ++++++++- 8 files changed, 71 insertions(+), 10 deletions(-) diff --git a/tests/incremental/00-basic/03-changed_start_state2.json b/tests/incremental/00-basic/03-changed_start_state2.json index 82849741fd..05fd4ebc64 100644 --- a/tests/incremental/00-basic/03-changed_start_state2.json +++ b/tests/incremental/00-basic/03-changed_start_state2.json @@ -5,5 +5,12 @@ "int": false } } + }, + "incremental": { + "restart": { + "sided": { + "enabled": true + } + } } } diff --git a/tests/incremental/00-basic/03-changed_start_state2.patch b/tests/incremental/00-basic/03-changed_start_state2.patch index 5aa51b9cb7..30a84a2797 100644 --- a/tests/incremental/00-basic/03-changed_start_state2.patch +++ b/tests/incremental/00-basic/03-changed_start_state2.patch @@ -13,7 +13,7 @@ // overwriting, therefore the current imprecision. - assert(g == 1); - assert(g != 2); -+ assert(g != 1); // TODO (restarting) -+ assert(g == 2); // TODO ++ assert(g != 1); ++ assert(g == 2); return 0; } diff --git a/tests/incremental/11-restart/02-global-remove.json b/tests/incremental/11-restart/02-global-remove.json index 0e0dcd235c..d8addf1280 100644 --- a/tests/incremental/11-restart/02-global-remove.json +++ b/tests/incremental/11-restart/02-global-remove.json @@ -1,3 +1,9 @@ { - -} \ No newline at end of file + "incremental": { + "restart": { + "sided": { + "enabled": true + } + } + } +} diff --git a/tests/incremental/11-restart/03-global-change.json b/tests/incremental/11-restart/03-global-change.json index 5be265f269..fde70c9018 100644 --- a/tests/incremental/11-restart/03-global-change.json +++ b/tests/incremental/11-restart/03-global-change.json @@ -3,5 +3,12 @@ "int": { "interval": true } + }, + "incremental": { + "restart": { + "sided": { + "enabled": true + } + } } } \ No newline at end of file diff --git a/tests/incremental/11-restart/05-local-wpoint.json b/tests/incremental/11-restart/05-local-wpoint.json index ff773f6993..1ba4f95d61 100644 --- a/tests/incremental/11-restart/05-local-wpoint.json +++ b/tests/incremental/11-restart/05-local-wpoint.json @@ -5,6 +5,20 @@ } }, "incremental": { - "wpoint": false + "wpoint": false, + "restart": { + "sided": { + "enabled": true + } + } + }, + "solvers": { + "td3": { + "restart": { + "wpoint": { + "enabled": true + } + } + } } } \ No newline at end of file diff --git a/tests/incremental/11-restart/06-local-wpoint-read.json b/tests/incremental/11-restart/06-local-wpoint-read.json index ff773f6993..9349d0e2d7 100644 --- a/tests/incremental/11-restart/06-local-wpoint-read.json +++ b/tests/incremental/11-restart/06-local-wpoint-read.json @@ -5,6 +5,20 @@ } }, "incremental": { - "wpoint": false + "wpoint": false, + "restart": { + "sided": { + "enabled": true + } + } + }, + "solvers": { + "td3": { + "restart": { + "wpoint": { + "enabled": true + } + } + } } -} \ No newline at end of file +} diff --git a/tests/incremental/11-restart/09-call-remove.json b/tests/incremental/11-restart/09-call-remove.json index 0e0dcd235c..d8addf1280 100644 --- a/tests/incremental/11-restart/09-call-remove.json +++ b/tests/incremental/11-restart/09-call-remove.json @@ -1,3 +1,9 @@ { - -} \ No newline at end of file + "incremental": { + "restart": { + "sided": { + "enabled": true + } + } + } +} diff --git a/tests/incremental/11-restart/11-paper-example.json b/tests/incremental/11-restart/11-paper-example.json index 5be265f269..706a224f30 100644 --- a/tests/incremental/11-restart/11-paper-example.json +++ b/tests/incremental/11-restart/11-paper-example.json @@ -3,5 +3,12 @@ "int": { "interval": true } + }, + "incremental": { + "restart": { + "sided": { + "enabled": true + } + } } -} \ No newline at end of file +} From 076660b13eed8bd448cefd5a2579a922773341a6 Mon Sep 17 00:00:00 2001 From: Vesal Vojdani Date: Thu, 14 Apr 2022 20:24:36 +0300 Subject: [PATCH 296/402] Return location of if stmts to only be the head! --- src/util/cilfacade0.ml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/util/cilfacade0.ml b/src/util/cilfacade0.ml index dfe6dd031b..8d7d401e45 100644 --- a/src/util/cilfacade0.ml +++ b/src/util/cilfacade0.ml @@ -24,4 +24,6 @@ let get_stmtLoc stmt = | Instr [] | Block {bstmts = []; _} -> get_labelsLoc stmt.labels + | If(_, _, _, _, eloc) -> eloc + | Loop (_, _, eloc, _, _) -> eloc | _ -> get_stmtkindLoc stmt.skind From b30ef61691ec9e1c96a4e4aa2ed71ca8fdac59dc Mon Sep 17 00:00:00 2001 From: Vesal Vojdani Date: Thu, 14 Apr 2022 20:30:18 +0300 Subject: [PATCH 297/402] Revert "Return location of if stmts to only be the head!" This was not supposed to go here. Stupid git! This reverts commit 076660b13eed8bd448cefd5a2579a922773341a6. --- src/util/cilfacade0.ml | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/util/cilfacade0.ml b/src/util/cilfacade0.ml index 8d7d401e45..dfe6dd031b 100644 --- a/src/util/cilfacade0.ml +++ b/src/util/cilfacade0.ml @@ -24,6 +24,4 @@ let get_stmtLoc stmt = | Instr [] | Block {bstmts = []; _} -> get_labelsLoc stmt.labels - | If(_, _, _, _, eloc) -> eloc - | Loop (_, _, eloc, _, _) -> eloc | _ -> get_stmtkindLoc stmt.skind From ab489971cb3184b6eba13b44097d11bb0984352e Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 20 Apr 2022 16:00:36 +0300 Subject: [PATCH 298/402] Add conf for precise zstd race detection --- conf/zstd-race.json | 88 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 88 insertions(+) create mode 100644 conf/zstd-race.json diff --git a/conf/zstd-race.json b/conf/zstd-race.json new file mode 100644 index 0000000000..36afedd961 --- /dev/null +++ b/conf/zstd-race.json @@ -0,0 +1,88 @@ +{ + "ana": { + "activated": [ + "expRelation", "base", "threadid", "threadflag", "threadreturn", + "escape", "mutexEvents", "mutex", "access", "mallocWrapper", "mhp", + "symb_locks", "var_eq", "mallocFresh" + ], + "ctx_insens": [ + "var_eq" + ], + "base": { + "privatization": "none", + "context": { + "non-ptr": false + } + }, + "thread": { + "domain": "plain" + }, + "malloc": { + "wrappers": [ + "ZSTD_customMalloc", + "ZSTD_customCalloc" + ] + } + }, + "sem": { + "unknown_function": { + "spawn": false + } + }, + "incremental": { + "reluctant": { + "compare": "leq" + }, + "restart": { + "sided": { + "enabled": false + } + } + }, + "solvers": { + "td3": { + "restart": { + "wpoint": { + "enabled": false + } + } + } + }, + "exp": { + "earlyglobs": true, + "extraspecials": [ + "ZSTD_customMalloc", + "ZSTD_customCalloc", + "ZSTD_customFree" + ] + }, + "dbg": { + "print_dead_code": true + }, + "pre": { + "cppflags": ["-DZSTD_NO_INTRINSICS", "-D_FORTIFY_SOURCE=0", "-DGOBLINT_NO_ASSERT", "-DGOBLINT_NO_BSEARCH"] + }, + "cil": { + "merge": { + "inlines": false + } + }, + "printstats": true, + "warn": { + "assert": false, + "behavior": false, + "integer": false, + "cast": false, + "race": true, + "deadcode": false, + "analyzer": false, + "unsound": false, + "imprecise": false, + "unknown": false, + "error": false, + "warning": true, + "info": false, + "debug": false, + "success": false + } +} From d1b0b32e6cfe1e809e6fa026b7105da2f7044662 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Fri, 22 Apr 2022 10:09:59 +0300 Subject: [PATCH 299/402] Renumber 45-apron2 -> 46-apron2 --- .../{45-apron2 => 46-apron2}/01-td3-self-abort-complex.c | 0 tests/regression/{45-apron2 => 46-apron2}/02-localization-hh.c | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename tests/regression/{45-apron2 => 46-apron2}/01-td3-self-abort-complex.c (100%) rename tests/regression/{45-apron2 => 46-apron2}/02-localization-hh.c (100%) diff --git a/tests/regression/45-apron2/01-td3-self-abort-complex.c b/tests/regression/46-apron2/01-td3-self-abort-complex.c similarity index 100% rename from tests/regression/45-apron2/01-td3-self-abort-complex.c rename to tests/regression/46-apron2/01-td3-self-abort-complex.c diff --git a/tests/regression/45-apron2/02-localization-hh.c b/tests/regression/46-apron2/02-localization-hh.c similarity index 100% rename from tests/regression/45-apron2/02-localization-hh.c rename to tests/regression/46-apron2/02-localization-hh.c From 0c6cef63c5beb4c147758e1349ec173bf37013a1 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Fri, 22 Apr 2022 18:22:54 +0300 Subject: [PATCH 300/402] Enable deadcode and success in zstd-race conf for debugging --- conf/zstd-race.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/conf/zstd-race.json b/conf/zstd-race.json index 36afedd961..cbd9c629a8 100644 --- a/conf/zstd-race.json +++ b/conf/zstd-race.json @@ -74,7 +74,7 @@ "integer": false, "cast": false, "race": true, - "deadcode": false, + "deadcode": true, "analyzer": false, "unsound": false, "imprecise": false, @@ -83,6 +83,6 @@ "warning": true, "info": false, "debug": false, - "success": false + "success": true } } From a1a9c5a3abe24384022935ce7c6933bead73a250 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Mon, 25 Apr 2022 11:19:34 +0300 Subject: [PATCH 301/402] Disable unknown function globals invalidate in zstd-race conf --- conf/zstd-race.json | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/conf/zstd-race.json b/conf/zstd-race.json index cbd9c629a8..06a6084ccb 100644 --- a/conf/zstd-race.json +++ b/conf/zstd-race.json @@ -26,7 +26,10 @@ }, "sem": { "unknown_function": { - "spawn": false + "spawn": false, + "invalidate": { + "globals": false + } } }, "incremental": { From 28c3089b6745ec81d5c2b47cebf7cb906bf498bc Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Tue, 26 Apr 2022 16:24:29 +0300 Subject: [PATCH 302/402] Disable ana.thread.include-node in zstd-race conf --- conf/zstd-race.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/conf/zstd-race.json b/conf/zstd-race.json index 06a6084ccb..64ff2ea07a 100644 --- a/conf/zstd-race.json +++ b/conf/zstd-race.json @@ -15,7 +15,8 @@ } }, "thread": { - "domain": "plain" + "domain": "plain", + "include-node": false }, "malloc": { "wrappers": [ From 616c0ed2533f50f2c9b0d0cd5fec6f48bee6888d Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 27 Apr 2022 18:08:33 +0300 Subject: [PATCH 303/402] Add test for incremental warnings not removed with reluctant destabilization (issue #708) --- .../06-mutex-simple-reluctant.c | 23 ++++++++++++++++++ .../06-mutex-simple-reluctant.json | 12 ++++++++++ .../06-mutex-simple-reluctant.patch | 24 +++++++++++++++++++ 3 files changed, 59 insertions(+) create mode 100644 tests/incremental/13-restart-write/06-mutex-simple-reluctant.c create mode 100644 tests/incremental/13-restart-write/06-mutex-simple-reluctant.json create mode 100644 tests/incremental/13-restart-write/06-mutex-simple-reluctant.patch diff --git a/tests/incremental/13-restart-write/06-mutex-simple-reluctant.c b/tests/incremental/13-restart-write/06-mutex-simple-reluctant.c new file mode 100644 index 0000000000..82c1642a93 --- /dev/null +++ b/tests/incremental/13-restart-write/06-mutex-simple-reluctant.c @@ -0,0 +1,23 @@ +#include +#include + +int myglobal; +pthread_mutex_t mutex1 = PTHREAD_MUTEX_INITIALIZER; +pthread_mutex_t mutex2 = PTHREAD_MUTEX_INITIALIZER; + +void *t_fun(void *arg) { + pthread_mutex_lock(&mutex1); + myglobal=myglobal+1; // RACE! + pthread_mutex_unlock(&mutex1); + return NULL; +} + +int main(void) { + pthread_t id; + pthread_create(&id, NULL, t_fun, NULL); + pthread_mutex_lock(&mutex2); + myglobal=myglobal+1; // RACE! + pthread_mutex_unlock(&mutex2); + pthread_join (id, NULL); + return 0; +} diff --git a/tests/incremental/13-restart-write/06-mutex-simple-reluctant.json b/tests/incremental/13-restart-write/06-mutex-simple-reluctant.json new file mode 100644 index 0000000000..699332fa16 --- /dev/null +++ b/tests/incremental/13-restart-write/06-mutex-simple-reluctant.json @@ -0,0 +1,12 @@ +{ + "incremental": { + "restart": { + "sided": { + "enabled": false + } + }, + "reluctant": { + "on": true + } + } +} \ No newline at end of file diff --git a/tests/incremental/13-restart-write/06-mutex-simple-reluctant.patch b/tests/incremental/13-restart-write/06-mutex-simple-reluctant.patch new file mode 100644 index 0000000000..3674a31c23 --- /dev/null +++ b/tests/incremental/13-restart-write/06-mutex-simple-reluctant.patch @@ -0,0 +1,24 @@ +--- tests/incremental/13-restart-write/06-mutex-simple-reluctant.c ++++ tests/incremental/13-restart-write/06-mutex-simple-reluctant.c +@@ -7,7 +7,7 @@ pthread_mutex_t mutex2 = PTHREAD_MUTEX_INITIALIZER; + + void *t_fun(void *arg) { + pthread_mutex_lock(&mutex1); +- myglobal=myglobal+1; // RACE! ++ myglobal=myglobal+1; // NORACE + pthread_mutex_unlock(&mutex1); + return NULL; + } +@@ -15,9 +15,9 @@ void *t_fun(void *arg) { + int main(void) { + pthread_t id; + pthread_create(&id, NULL, t_fun, NULL); +- pthread_mutex_lock(&mutex2); +- myglobal=myglobal+1; // RACE! +- pthread_mutex_unlock(&mutex2); ++ pthread_mutex_lock(&mutex1); ++ myglobal=myglobal+1; // NORACE ++ pthread_mutex_unlock(&mutex1); + pthread_join (id, NULL); + return 0; + } From 60b756bfb29e709d7bff5f3f2626eb1ccf51e5d9 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 27 Apr 2022 18:19:26 +0300 Subject: [PATCH 304/402] Fix incremental unknown deletion to apply to incremental postsolving structures as well (issue #708) --- src/solvers/td3.ml | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/solvers/td3.ml b/src/solvers/td3.ml index 1b52aa81c5..839433daa2 100644 --- a/src/solvers/td3.ml +++ b/src/solvers/td3.ml @@ -737,7 +737,7 @@ module WP = print_endline "Removing data for changed and removed functions..."; let delete_marked s = HM.iter (fun k _ -> HM.remove s k) marked_for_deletion in delete_marked rho; - delete_marked infl; + delete_marked infl; (* TODO: delete from inner sets? *) delete_marked wpoint; (* destabilize_with_side doesn't have all infl to follow anymore, so should somewhat work with reluctant *) @@ -826,8 +826,15 @@ module WP = ); delete_marked stable; - delete_marked side_dep; - delete_marked side_infl; + delete_marked side_dep; (* TODO: delete from inner sets? *) + delete_marked side_infl; (* TODO: delete from inner sets? *) + + (* delete from incremental postsolving/warning structures to remove spurious warnings *) + delete_marked superstable; + delete_marked var_messages; + delete_marked rho_write; + HM.iter (fun x w -> delete_marked w) rho_write; + print_data data "Data after clean-up"; (* TODO: reluctant doesn't call destabilize on removed functions or old copies of modified functions (e.g. after removing write), so those globals don't get restarted *) From 428cda0964dc4c20bec84920ee3329b3d65d86e4 Mon Sep 17 00:00:00 2001 From: Vesal Vojdani Date: Wed, 27 Apr 2022 22:45:40 +0000 Subject: [PATCH 305/402] Add test where warning should remain. --- .../07-mutex-simple-reluctant2.c | 23 +++++++++++++++++++ .../07-mutex-simple-reluctant2.json | 12 ++++++++++ .../07-mutex-simple-reluctant2.patch | 11 +++++++++ 3 files changed, 46 insertions(+) create mode 100644 tests/incremental/13-restart-write/07-mutex-simple-reluctant2.c create mode 100644 tests/incremental/13-restart-write/07-mutex-simple-reluctant2.json create mode 100644 tests/incremental/13-restart-write/07-mutex-simple-reluctant2.patch diff --git a/tests/incremental/13-restart-write/07-mutex-simple-reluctant2.c b/tests/incremental/13-restart-write/07-mutex-simple-reluctant2.c new file mode 100644 index 0000000000..82c1642a93 --- /dev/null +++ b/tests/incremental/13-restart-write/07-mutex-simple-reluctant2.c @@ -0,0 +1,23 @@ +#include +#include + +int myglobal; +pthread_mutex_t mutex1 = PTHREAD_MUTEX_INITIALIZER; +pthread_mutex_t mutex2 = PTHREAD_MUTEX_INITIALIZER; + +void *t_fun(void *arg) { + pthread_mutex_lock(&mutex1); + myglobal=myglobal+1; // RACE! + pthread_mutex_unlock(&mutex1); + return NULL; +} + +int main(void) { + pthread_t id; + pthread_create(&id, NULL, t_fun, NULL); + pthread_mutex_lock(&mutex2); + myglobal=myglobal+1; // RACE! + pthread_mutex_unlock(&mutex2); + pthread_join (id, NULL); + return 0; +} diff --git a/tests/incremental/13-restart-write/07-mutex-simple-reluctant2.json b/tests/incremental/13-restart-write/07-mutex-simple-reluctant2.json new file mode 100644 index 0000000000..36c62c6389 --- /dev/null +++ b/tests/incremental/13-restart-write/07-mutex-simple-reluctant2.json @@ -0,0 +1,12 @@ +{ + "incremental": { + "restart": { + "sided": { + "enabled": false + } + }, + "reluctant": { + "on": true + } + } +} diff --git a/tests/incremental/13-restart-write/07-mutex-simple-reluctant2.patch b/tests/incremental/13-restart-write/07-mutex-simple-reluctant2.patch new file mode 100644 index 0000000000..3d2a480c67 --- /dev/null +++ b/tests/incremental/13-restart-write/07-mutex-simple-reluctant2.patch @@ -0,0 +1,11 @@ +--- tests/incremental/13-restart-write/07-mutex-simple-reluctant2.c ++++ tests/incremental/13-restart-write/07-mutex-simple-reluctant2.c +@@ -7,7 +7,7 @@ pthread_mutex_t mutex2 = PTHREAD_MUTEX_INITIALIZER; + + void *t_fun(void *arg) { + pthread_mutex_lock(&mutex1); +- myglobal=myglobal+1; // RACE! ++ myglobal=myglobal+2; // RACE! + pthread_mutex_unlock(&mutex1); + return NULL; + } From b4fd3cb6d2ed972e009f4886ce1107a82f5aea3f Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 28 Apr 2022 10:19:11 +0300 Subject: [PATCH 306/402] Add test for incremental warnings not added with reluctant destabilization (PR #709) --- src/solvers/td3.ml | 3 +++ .../08-mutex-simple-reluctant3.c | 22 +++++++++++++++++++ .../08-mutex-simple-reluctant3.json | 12 ++++++++++ .../08-mutex-simple-reluctant3.patch | 19 ++++++++++++++++ 4 files changed, 56 insertions(+) create mode 100644 tests/incremental/13-restart-write/08-mutex-simple-reluctant3.c create mode 100644 tests/incremental/13-restart-write/08-mutex-simple-reluctant3.json create mode 100644 tests/incremental/13-restart-write/08-mutex-simple-reluctant3.patch diff --git a/src/solvers/td3.ml b/src/solvers/td3.ml index 839433daa2..06019953f9 100644 --- a/src/solvers/td3.ml +++ b/src/solvers/td3.ml @@ -852,6 +852,9 @@ module WP = destabilize x; HM.replace stable x () ) + else ( + print_endline "Destabilization not required..."; + ) ) old_ret; print_endline "Final solve..." diff --git a/tests/incremental/13-restart-write/08-mutex-simple-reluctant3.c b/tests/incremental/13-restart-write/08-mutex-simple-reluctant3.c new file mode 100644 index 0000000000..b817928884 --- /dev/null +++ b/tests/incremental/13-restart-write/08-mutex-simple-reluctant3.c @@ -0,0 +1,22 @@ +#include +#include + +int myglobal; +pthread_mutex_t mutex1 = PTHREAD_MUTEX_INITIALIZER; +pthread_mutex_t mutex2 = PTHREAD_MUTEX_INITIALIZER; + +void *t_fun(void *arg) { + pthread_mutex_lock(&mutex1); + pthread_mutex_unlock(&mutex1); + return NULL; +} + +int main(void) { + pthread_t id; + pthread_create(&id, NULL, t_fun, NULL); + pthread_mutex_lock(&mutex2); + myglobal=myglobal+1; // NORACE + pthread_mutex_unlock(&mutex2); + pthread_join (id, NULL); + return 0; +} diff --git a/tests/incremental/13-restart-write/08-mutex-simple-reluctant3.json b/tests/incremental/13-restart-write/08-mutex-simple-reluctant3.json new file mode 100644 index 0000000000..699332fa16 --- /dev/null +++ b/tests/incremental/13-restart-write/08-mutex-simple-reluctant3.json @@ -0,0 +1,12 @@ +{ + "incremental": { + "restart": { + "sided": { + "enabled": false + } + }, + "reluctant": { + "on": true + } + } +} \ No newline at end of file diff --git a/tests/incremental/13-restart-write/08-mutex-simple-reluctant3.patch b/tests/incremental/13-restart-write/08-mutex-simple-reluctant3.patch new file mode 100644 index 0000000000..e85790ca7c --- /dev/null +++ b/tests/incremental/13-restart-write/08-mutex-simple-reluctant3.patch @@ -0,0 +1,19 @@ +--- tests/incremental/13-restart-write/08-mutex-simple-reluctant3.c ++++ tests/incremental/13-restart-write/08-mutex-simple-reluctant3.c +@@ -7,6 +7,7 @@ pthread_mutex_t mutex2 = PTHREAD_MUTEX_INITIALIZER; + + void *t_fun(void *arg) { + pthread_mutex_lock(&mutex1); ++ myglobal=myglobal+1; // RACE! + pthread_mutex_unlock(&mutex1); + return NULL; + } +@@ -15,7 +16,7 @@ int main(void) { + pthread_t id; + pthread_create(&id, NULL, t_fun, NULL); + pthread_mutex_lock(&mutex2); +- myglobal=myglobal+1; // NORACE ++ myglobal=myglobal+1; // RACE! + pthread_mutex_unlock(&mutex2); + pthread_join (id, NULL); + return 0; From aca39c3fee5b926a3e0d5367d9b7c693800d97b2 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 28 Apr 2022 10:23:07 +0300 Subject: [PATCH 307/402] Fix reluctantly not destabilized functions not being postsolved (PR #709) --- src/solvers/td3.ml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/solvers/td3.ml b/src/solvers/td3.ml index 06019953f9..c5ee732c11 100644 --- a/src/solvers/td3.ml +++ b/src/solvers/td3.ml @@ -540,6 +540,9 @@ module WP = start_event (); + (* reluctantly unchanged return nodes to additionally query for postsolving to get warnings, etc. *) + let reluctant_vs: S.Var.t list ref = ref [] in + if GobConfig.get_bool "incremental.load" then ( let c = S.increment.changes in List.(Printf.printf "change_info = { unchanged = %d; changed = %d; added = %d; removed = %d }\n" (length c.unchanged) (length c.changed) (length c.added) (length c.removed)); @@ -854,6 +857,7 @@ module WP = ) else ( print_endline "Destabilization not required..."; + reluctant_vs := x :: !reluctant_vs ) ) old_ret; @@ -1111,7 +1115,7 @@ module WP = let module Post = PostSolver.MakeIncrList (MakeIncrListArg) in - Post.post st vs rho; + Post.post st (!reluctant_vs @ vs) rho; print_data data "Data after postsolve"; From a33457a2b4c5d788195b85415d261981d5a214fa Mon Sep 17 00:00:00 2001 From: Michael Schwarz Date: Thu, 28 Apr 2022 13:18:09 +0200 Subject: [PATCH 308/402] Add example where incremental postsolver does not remove warnings --- tests/incremental/00-basic/09-unreach.c | 14 ++++++++++++++ tests/incremental/00-basic/09-unreach.json | 8 ++++++++ tests/incremental/00-basic/09-unreach.patch | 17 +++++++++++++++++ 3 files changed, 39 insertions(+) create mode 100644 tests/incremental/00-basic/09-unreach.c create mode 100644 tests/incremental/00-basic/09-unreach.json create mode 100644 tests/incremental/00-basic/09-unreach.patch diff --git a/tests/incremental/00-basic/09-unreach.c b/tests/incremental/00-basic/09-unreach.c new file mode 100644 index 0000000000..07e347a64b --- /dev/null +++ b/tests/incremental/00-basic/09-unreach.c @@ -0,0 +1,14 @@ +#include + +void foo() { + int x = 2; + assert(x == 3); //FAIL +} + +int main() { + int a = 1; + + foo(); + + return 0; +} diff --git a/tests/incremental/00-basic/09-unreach.json b/tests/incremental/00-basic/09-unreach.json new file mode 100644 index 0000000000..aee1ae335b --- /dev/null +++ b/tests/incremental/00-basic/09-unreach.json @@ -0,0 +1,8 @@ +{ + "dbg": { + "debug": true + }, + "incremental" : { + "verify": true + } +} diff --git a/tests/incremental/00-basic/09-unreach.patch b/tests/incremental/00-basic/09-unreach.patch new file mode 100644 index 0000000000..ede5210a26 --- /dev/null +++ b/tests/incremental/00-basic/09-unreach.patch @@ -0,0 +1,17 @@ +--- tests/incremental/00-basic/09-unreach.c ++++ tests/incremental/00-basic/09-unreach.c +@@ -2,13 +2,12 @@ + + void foo() { + int x = 2; +- assert(x == 3); //FAIL ++ assert(x == 3); //NOWARN + } + + int main() { + int a = 1; + +- foo(); + + return 0; + } From bda1100eb9e75f5b4d9cf152b4447be961a020f5 Mon Sep 17 00:00:00 2001 From: Michael Schwarz Date: Sat, 30 Apr 2022 16:37:17 +0200 Subject: [PATCH 309/402] Steps towards cheap full reachability --- src/framework/constraints.ml | 5 +- src/solvers/postSolver.ml | 72 ++++++++++++++++++---------- src/solvers/td3.ml | 92 +++++++++++++++++++++++------------- 3 files changed, 109 insertions(+), 60 deletions(-) diff --git a/src/framework/constraints.ml b/src/framework/constraints.ml index cf85bcb73c..6d00d1935d 100644 --- a/src/framework/constraints.ml +++ b/src/framework/constraints.ml @@ -797,13 +797,14 @@ module EqIncrSolverFromEqSolver (Sol: GenericEqBoxSolver): GenericEqBoxIncrSolve functor (Arg: IncrSolverArg) (S: EqConstrSys) (VH: Hashtbl.S with type key = S.v) -> struct module Sol = Sol (S) (VH) - module Post = PostSolver.MakeList (PostSolver.ListArgFromStdArg (S) (VH) (Arg)) + module VS = BatSet.Make(S.Var) + module Post = PostSolver.MakeList (PostSolver.ListArgFromStdArg (S) (VH) (VS) (Arg)) type marshal = unit let solve box xs vs = let vh = Sol.solve box xs vs in - Post.post xs vs vh; + Post.post xs vs vh None; (vh, ()) end diff --git a/src/solvers/postSolver.ml b/src/solvers/postSolver.ml index 9b66205398..68d824eb83 100644 --- a/src/solvers/postSolver.ml +++ b/src/solvers/postSolver.ml @@ -7,6 +7,7 @@ module type S = sig module S: EqConstrSys module VH: Hashtbl.S with type key = S.v + module VS: BatSet.S with type elt = S.v val init: unit -> unit val one_side: vh:S.Dom.t VH.t -> x:S.v -> y:S.v -> d:S.Dom.t -> unit @@ -16,15 +17,16 @@ end (** Functorial postsolver for any system. *) module type F = - functor (S: EqConstrSys) (VH: Hashtbl.S with type key = S.v) -> - S with module S = S and module VH = VH + functor (S: EqConstrSys) (VH: Hashtbl.S with type key = S.v) (VS: BatSet.S with type elt = S.v) -> + S with module S = S and module VH = VH and module VS = VS (** Base implementation for postsolver. *) module Unit: F = - functor (S: EqConstrSys) (VH: Hashtbl.S with type key = S.v) -> + functor (S: EqConstrSys) (VH: Hashtbl.S with type key = S.v) (VS: BatSet.S with type elt = S.v) -> struct module S = S module VH = VH + module VS = VS let init () = () let one_side ~vh ~x ~y ~d = () let one_constraint ~vh ~x ~rhs = () @@ -32,10 +34,11 @@ module Unit: F = end (** Sequential composition of two postsolvers. *) -module Compose (PS1: S) (PS2: S with module S = PS1.S and module VH = PS1.VH): S with module S = PS1.S and module VH = PS1.VH = +module Compose (PS1: S) (PS2: S with module S = PS1.S and module VH = PS1.VH and module VS = PS1.VS): S with module S = PS1.S and module VH = PS1.VH and module VS = PS1.VS = struct module S = PS1.S module VH = PS1.VH + module VS = PS1.VS let init () = PS1.init (); @@ -53,9 +56,9 @@ end (** Postsolver for pruning solution using reachability. *) module Prune: F = - functor (S: EqConstrSys) (VH: Hashtbl.S with type key = S.v) -> + functor (S: EqConstrSys) (VH: Hashtbl.S with type key = S.v) (VS: BatSet.S with type elt = S.v) -> struct - include Unit (S) (VH) + include Unit (S) (VH) (VS) let finalize ~vh ~reachable = if get_bool "dbg.debug" then @@ -68,9 +71,9 @@ module Prune: F = (** Postsolver for verifying solution in demand-driven fashion. *) module Verify: F = - functor (S: EqConstrSys) (VH: Hashtbl.S with type key = S.v) -> + functor (S: EqConstrSys) (VH: Hashtbl.S with type key = S.v) (VS: BatSet.S with type elt = S.v) -> struct - include Unit (S) (VH) + include Unit (S) (VH) (VS) let init () = Goblintutil.verified := Some true @@ -98,9 +101,9 @@ module Verify: F = (** Postsolver for enabling messages (warnings) output. *) module Warn: F = - functor (S: EqConstrSys) (VH: Hashtbl.S with type key = S.v) -> + functor (S: EqConstrSys) (VH: Hashtbl.S with type key = S.v) (VS: BatSet.S with type elt = S.v) -> struct - include Unit (S) (VH) + include Unit (S) (VH) (VS) let old_should_warn = ref None @@ -114,9 +117,9 @@ module Warn: F = (** Postsolver for save_run option. *) module SaveRun: F = - functor (S: EqConstrSys) (VH: Hashtbl.S with type key = S.v) -> + functor (S: EqConstrSys) (VH: Hashtbl.S with type key = S.v) (VS: BatSet.S with type elt = S.v) -> struct - include Unit (S) (VH) + include Unit (S) (VH) (VS) let finalize ~vh ~reachable = (* copied from Control.solve_and_postprocess *) @@ -172,9 +175,10 @@ end module MakeIncr (PS: IncrS) = struct module S = PS.S + module VS = PS.VS module VH = PS.VH - let post xs vs vh = + let post xs vs vh dep = if get_bool "dbg.verbose" then print_endline "Postsolving\n"; @@ -211,13 +215,30 @@ struct if M.tracing then M.trace "postsolver" "one_constraint %a %a\n" S.Var.pretty_trace x S.Dom.pretty rhs; PS.one_constraint ~vh ~x ~rhs in - List.iter one_var vs; - - PS.finalize ~vh ~reachable; + (Stats.time "potentially_incremental_reach" (List.iter one_var)) vs; + + match dep with + | None -> PS.finalize ~vh ~reachable:reachable; + | Some dep -> ( + (* Perform reachability on whole constraint system, but cheaply by using logged dependencies *) + (* This only works if the other reachability has been performed before, so dependencies created only during postsolve are recorded *) + let reachable' = VH.create (VH.length vh) in + let rec one_var' x = + if not (VH.mem reachable' x) then ( + VH.replace reachable' x (); + match VH.find_option dep x with + | Some vs -> VS.iter one_var' vs + | None -> () + ) + in + (Stats.time "cheap_full_reach" (List.iter one_var')) vs; + PS.finalize ~vh ~reachable:reachable'; + ) + ; Goblintutil.postsolving := false - let post xs vs vh = - Stats.time "postsolver" (post xs vs) vh + let post xs vs vh dep = + Stats.time "postsolver" (post xs vs vh) dep end (** List of postsolvers. *) @@ -226,8 +247,9 @@ sig (* Specify S and VH here to constrain all postsolvers to use the same. *) module S: EqConstrSys module VH: Hashtbl.S with type key = S.v + module VS: BatSet.S with type elt = S.v (* Auxiliary module type because first-class module types cannot contain module constraints. *) - module type M = S with module S = S and module VH = VH + module type M = S with module S = S and module VH = VH and module VS = VS val postsolvers: (module M) list end @@ -246,6 +268,7 @@ module MakeIncrList (Arg: MakeIncrListArg) = struct module S = Arg.S module VH = Arg.VH + module VS = Arg.VS let postsolver_opt: (module Arg.M) option = match Arg.postsolvers with @@ -256,7 +279,7 @@ struct in Some (List.reduce compose postsolvers) - let post xs vs vh = + let post xs vs vh dep = match postsolver_opt with | None -> () | Some (module PS) -> @@ -267,7 +290,7 @@ struct end in let module M = MakeIncr (IncrPS) in - M.post xs vs vh + M.post xs vs vh dep end (** Make complete (non-incremental) postsolving function from list of postsolvers. @@ -292,13 +315,14 @@ sig end (** List of standard postsolvers. *) -module ListArgFromStdArg (S: EqConstrSys) (VH: Hashtbl.S with type key = S.v) (Arg: MakeStdArg): MakeListArg with module S = S and module VH = VH = +module ListArgFromStdArg (S: EqConstrSys) (VH: Hashtbl.S with type key = S.v) (VS: BatSet.S with type elt = S.v) (Arg: MakeStdArg): MakeListArg with module S = S and module VH = VH and module VS = VS = struct open Arg module S = S module VH = VH - module type M = S with module S = S and module VH = VH + module VS = VS + module type M = S with module S = S and module VH = VH and module VS = VS let postsolvers: (bool * (module F)) list = [ (should_prune, (module Prune)); @@ -311,5 +335,5 @@ struct postsolvers |> List.filter fst |> List.map snd - |> List.map (fun (module F: F) -> (module F (S) (VH): M)) + |> List.map (fun (module F: F) -> (module F (S) (VH) (VS): M)) end diff --git a/src/solvers/td3.ml b/src/solvers/td3.ml index 1b52aa81c5..d5e987dbf0 100644 --- a/src/solvers/td3.ml +++ b/src/solvers/td3.ml @@ -35,6 +35,7 @@ module WP = mutable side_infl: VS.t HM.t; (** Influences to side-effected variables. Not normally in [infl], but used for restarting them. *) mutable var_messages: Message.t HM.t; mutable rho_write: S.Dom.t HM.t HM.t; + mutable dep: VS.t HM.t } type marshal = solver_data @@ -50,12 +51,13 @@ module WP = side_infl = HM.create 10; var_messages = HM.create 10; rho_write = HM.create 10; + dep = HM.create 10; } let print_data data str = if GobConfig.get_bool "dbg.verbose" then - Printf.printf "%s:\n|rho|=%d\n|stable|=%d\n|infl|=%d\n|wpoint|=%d\n|side_dep|=%d\n|side_infl|=%d\n" - str (HM.length data.rho) (HM.length data.stable) (HM.length data.infl) (HM.length data.wpoint) (HM.length data.side_dep) (HM.length data.side_infl) + Printf.printf "%s:\n|rho|=%d\n|stable|=%d\n|infl|=%d\n|wpoint|=%d\n|side_dep|=%d\n|side_infl|=%d|dep|=%d\n" + str (HM.length data.rho) (HM.length data.stable) (HM.length data.infl) (HM.length data.wpoint) (HM.length data.side_dep) (HM.length data.side_infl) (HM.length data.dep) let verify_data data = if GobConfig.get_bool "solvers.td3.verify" then ( @@ -154,6 +156,9 @@ module WP = let abort_verify = GobConfig.get_bool "solvers.td3.abort-verify" in let prev_dep_vals = HM.create 10 in + (* Tracks dependencies between an unknown and the things it depends on AND has side-effects to *) + let dep = data.dep in + let () = print_solver_stats := fun () -> Printf.printf "|rho|=%d\n|called|=%d\n|stable|=%d\n|infl|=%d\n|wpoint|=%d\n|side_dep|=%d\n|side_infl|=%d\n" (HM.length rho) (HM.length called) (HM.length stable) (HM.length infl) (HM.length wpoint) (HM.length side_dep) (HM.length side_infl); @@ -182,8 +187,12 @@ module WP = let add_infl y x = if tracing then trace "sol2" "add_infl %a %a\n" S.Var.pretty_trace y S.Var.pretty_trace x; HM.replace infl y (VS.add x (try HM.find infl y with Not_found -> VS.empty)); + HM.replace dep x (VS.add y (HM.find_default dep x VS.empty)); in - let add_sides y x = HM.replace sides y (VS.add x (try HM.find sides y with Not_found -> VS.empty)) in + let add_sides y x = + (* dep records also the things an unknown has side-effects on *) + HM.replace dep x (VS.add y (HM.find_default dep x VS.empty)); + HM.replace sides y (VS.add x (try HM.find sides y with Not_found -> VS.empty)) in let destabilize_ref: (?front:bool -> S.v -> unit) ref = ref (fun ?front _ -> failwith "no destabilize yet") in let destabilize x = !destabilize_ref x in (* must be eta-expanded to use changed destabilize_ref *) @@ -260,10 +269,13 @@ module WP = let (tmp, aborted) = match reuse_eq with | Some d when narrow_reuse && not narrow_reuse_verify -> + (* Do not reset deps for reuse of eq *) if tracing then trace "sol2" "eq reused %a\n" S.Var.pretty_trace x; incr Goblintutil.narrow_reuses; (d, false) | _ -> + (* The RHS is re-evaluated, all deps are re-trigerred *) + HM.replace dep x VS.empty; try if abort && abort_verify then ( (* collect dep vals for x *) @@ -739,6 +751,7 @@ module WP = delete_marked rho; delete_marked infl; delete_marked wpoint; + delete_marked dep; (* destabilize_with_side doesn't have all infl to follow anymore, so should somewhat work with reluctant *) if restart_sided then ( @@ -943,9 +956,9 @@ module WP = (* Prune other data structures than rho with reachable. These matter for the incremental data. *) - let module IncrPrune: PostSolver.S with module S = S and module VH = HM = + let module IncrPrune: PostSolver.S with module S = S and module VH = HM and module VS = VS = struct - include PostSolver.Unit (S) (HM) + include PostSolver.Unit (S) (HM) (VS) let finalize ~vh ~reachable = VH.filteri_inplace (fun x _ -> @@ -981,11 +994,13 @@ module WP = in (* postsolver also populates side_dep and side_infl *) - let module SideInfl: PostSolver.S with module S = S and module VH = HM = + let module SideInfl: PostSolver.S with module S = S and module VH = HM and module VS = VS= struct - include PostSolver.Unit (S) (HM) + include PostSolver.Unit (S) (HM) (VS) let one_side ~vh ~x ~y ~d = + (* Also record side-effects caused by post-solver *) + HM.replace dep x (VS.add y (HM.find_default dep x VS.empty)); HM.replace side_dep y (VS.add x (try HM.find side_dep y with Not_found -> VS.empty)); HM.replace side_infl x (VS.add y (try HM.find side_infl x with Not_found -> VS.empty)); end @@ -1014,20 +1029,13 @@ module WP = HM.create 0 (* doesn't matter, not used *) in - let module IncrWarn: PostSolver.S with module S = S and module VH = HM = + let module IncrWarn: PostSolver.S with module S = S and module VH = HM and module VS = VS = struct - include PostSolver.Warn (S) (HM) + include PostSolver.Warn (S) (HM) (VS) let init () = init (); (* enable warning like standard Warn *) - (* replay superstable messages *) - if incr_verify then ( - HM.iter (fun _ m -> - Messages.add m - ) var_messages; - ); - (* hook to collect new messages *) Messages.Table.add_hook := (fun m -> match !current_var with @@ -1036,6 +1044,13 @@ module WP = ) let finalize ~vh ~reachable = + (* replay superstable messages from unknowns that are still reachable *) + if incr_verify then ( + HM.iter (fun (l:S.v) m -> + if HM.mem reachable l then Messages.add m + ) var_messages; + ); + finalize ~vh ~reachable; (* disable warning like standard Warn *) (* unhook to avoid accidental var_messages modifications *) @@ -1045,23 +1060,11 @@ module WP = (** Incremental write-only side effect restart handling: retriggers superstable ones (after restarting above) and collects new (non-superstable) ones. *) - let module IncrWrite: PostSolver.S with module S = S and module VH = HM = + let module IncrWrite: PostSolver.S with module S = S and module VH = HM and module VS = VS = struct - include PostSolver.Unit (S) (HM) + include PostSolver.Unit (S) (HM) (VS) - let init () = - (* retrigger superstable side writes *) - if incr_verify then ( - HM.iter (fun x w -> - HM.iter (fun y d -> - let old_d = try HM.find rho y with Not_found -> S.Dom.bot () in - (* ignore (Pretty.printf "rho_write retrigger %a %a %a %a\n" S.Var.pretty_trace x S.Var.pretty_trace y S.Dom.pretty old_d S.Dom.pretty d); *) - HM.replace rho y (S.Dom.join old_d d); - HM.replace init_reachable y (); - HM.replace stable y (); (* make stable just in case, so following incremental load would have in superstable *) - ) w - ) rho_write - ) + let init () = () let one_side ~vh ~x ~y ~d = if S.Var.is_write_only y then ( @@ -1077,6 +1080,22 @@ module WP = in VH.add w y d (* intentional add *) ) + + let finalize ~vh ~reachable = + (* retrigger superstable side writes from unknowns that are still reachable *) + if incr_verify then ( + HM.iter (fun x w -> + if HM.mem reachable x then + HM.iter (fun y d -> + let old_d = try HM.find rho y with Not_found -> S.Dom.bot () in + (* ignore (Pretty.printf "rho_write retrigger %a %a %a %a\n" S.Var.pretty_trace x S.Var.pretty_trace y S.Dom.pretty old_d S.Dom.pretty d); *) + HM.replace rho y (S.Dom.join old_d d); + HM.replace init_reachable y (); + HM.replace stable y (); (* make stable just in case, so following incremental load would have in superstable *) + ) w + ) rho_write + ) + end in @@ -1087,7 +1106,7 @@ module WP = include Arg let should_warn = false (* disable standard Warn in favor of IncrWarn *) end - include PostSolver.ListArgFromStdArg (S) (HM) (Arg) + include PostSolver.ListArgFromStdArg (S) (HM) (VS) (Arg) let postsolvers = (module IncrPrune: M) :: (module SideInfl: M) :: (module IncrWrite: M) :: (module IncrWarn: M) :: postsolvers @@ -1101,12 +1120,12 @@ module WP = let module Post = PostSolver.MakeIncrList (MakeIncrListArg) in - Post.post st vs rho; + Post.post st vs rho (Some dep); print_data data "Data after postsolve"; verify_data data; - {st; infl; sides; rho; wpoint; stable; side_dep; side_infl; var_messages; rho_write} + {st; infl; sides; rho; wpoint; stable; side_dep; side_infl; var_messages; rho_write; dep} let solve box st vs = let reuse_stable = GobConfig.get_bool "incremental.stable" in @@ -1180,6 +1199,11 @@ module WP = HM.replace rho_write' (S.Var.relift x) w'; ) data.rho_write; data.rho_write <- rho_write'; + let dep' = HM.create (HM.length data.dep) in + HM.iter (fun k v -> + HM.replace dep' (S.Var.relift k) v + ) data.dep; + data.dep <- dep'; ); if not reuse_stable then ( print_endline "Destabilizing everything!"; From 080d47483b9ce4fab5691ece8c473e35ceb4cc3b Mon Sep 17 00:00:00 2001 From: Michael Schwarz Date: Sat, 30 Apr 2022 17:45:06 +0200 Subject: [PATCH 310/402] Add fundamental problem where multi-threaded code becomes dead --- tests/incremental/00-basic/10-reach.c | 14 ++++++++++++++ tests/incremental/00-basic/10-reach.json | 8 ++++++++ tests/incremental/00-basic/10-reach.patch | 0 3 files changed, 22 insertions(+) create mode 100644 tests/incremental/00-basic/10-reach.c create mode 100644 tests/incremental/00-basic/10-reach.json create mode 100644 tests/incremental/00-basic/10-reach.patch diff --git a/tests/incremental/00-basic/10-reach.c b/tests/incremental/00-basic/10-reach.c new file mode 100644 index 0000000000..f7f2bf8c4f --- /dev/null +++ b/tests/incremental/00-basic/10-reach.c @@ -0,0 +1,14 @@ +#include +#include + +void foo() { + int x = 2; + assert(x == 2); +} + +int main() { + pthread_t id; + pthread_create(&id, NULL, foo, NULL); // just go multithreaded + + return 0; +} diff --git a/tests/incremental/00-basic/10-reach.json b/tests/incremental/00-basic/10-reach.json new file mode 100644 index 0000000000..aee1ae335b --- /dev/null +++ b/tests/incremental/00-basic/10-reach.json @@ -0,0 +1,8 @@ +{ + "dbg": { + "debug": true + }, + "incremental" : { + "verify": true + } +} diff --git a/tests/incremental/00-basic/10-reach.patch b/tests/incremental/00-basic/10-reach.patch new file mode 100644 index 0000000000..e69de29bb2 From 5d8d36d15278c502b7b839a7cc3d829004394778 Mon Sep 17 00:00:00 2001 From: Michael Schwarz Date: Sun, 1 May 2022 12:33:55 +0200 Subject: [PATCH 311/402] Newline for dep log --- src/solvers/td3.ml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/solvers/td3.ml b/src/solvers/td3.ml index d5e987dbf0..730ff630aa 100644 --- a/src/solvers/td3.ml +++ b/src/solvers/td3.ml @@ -56,7 +56,7 @@ module WP = let print_data data str = if GobConfig.get_bool "dbg.verbose" then - Printf.printf "%s:\n|rho|=%d\n|stable|=%d\n|infl|=%d\n|wpoint|=%d\n|side_dep|=%d\n|side_infl|=%d|dep|=%d\n" + Printf.printf "%s:\n|rho|=%d\n|stable|=%d\n|infl|=%d\n|wpoint|=%d\n|side_dep|=%d\n|side_infl|=%d\n|dep|=%d\n" str (HM.length data.rho) (HM.length data.stable) (HM.length data.infl) (HM.length data.wpoint) (HM.length data.side_dep) (HM.length data.side_infl) (HM.length data.dep) let verify_data data = From b9252dc424344f4d08466cfa8ac33b0080e9caa0 Mon Sep 17 00:00:00 2001 From: Michael Schwarz Date: Sun, 1 May 2022 12:56:15 +0200 Subject: [PATCH 312/402] dep: Relift VS too --- src/solvers/td3.ml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/solvers/td3.ml b/src/solvers/td3.ml index 730ff630aa..09ee23f5d6 100644 --- a/src/solvers/td3.ml +++ b/src/solvers/td3.ml @@ -1201,7 +1201,7 @@ module WP = data.rho_write <- rho_write'; let dep' = HM.create (HM.length data.dep) in HM.iter (fun k v -> - HM.replace dep' (S.Var.relift k) v + HM.replace dep' (S.Var.relift k) (VS.map S.Var.relift v) ) data.dep; data.dep <- dep'; ); From ee552184127451a000664f6863e296647f39a966 Mon Sep 17 00:00:00 2001 From: Michael Schwarz Date: Mon, 2 May 2022 10:18:28 +0200 Subject: [PATCH 313/402] Simplify --- src/solvers/postSolver.ml | 19 +------------- src/solvers/td3.ml | 53 ++++++++++++++++++++++++++------------- 2 files changed, 36 insertions(+), 36 deletions(-) diff --git a/src/solvers/postSolver.ml b/src/solvers/postSolver.ml index 68d824eb83..f56c61e4b5 100644 --- a/src/solvers/postSolver.ml +++ b/src/solvers/postSolver.ml @@ -217,24 +217,7 @@ struct in (Stats.time "potentially_incremental_reach" (List.iter one_var)) vs; - match dep with - | None -> PS.finalize ~vh ~reachable:reachable; - | Some dep -> ( - (* Perform reachability on whole constraint system, but cheaply by using logged dependencies *) - (* This only works if the other reachability has been performed before, so dependencies created only during postsolve are recorded *) - let reachable' = VH.create (VH.length vh) in - let rec one_var' x = - if not (VH.mem reachable' x) then ( - VH.replace reachable' x (); - match VH.find_option dep x with - | Some vs -> VS.iter one_var' vs - | None -> () - ) - in - (Stats.time "cheap_full_reach" (List.iter one_var')) vs; - PS.finalize ~vh ~reachable:reachable'; - ) - ; + PS.finalize ~vh ~reachable:reachable; Goblintutil.postsolving := false let post xs vs vh dep = diff --git a/src/solvers/td3.ml b/src/solvers/td3.ml index 09ee23f5d6..d56e8e7a4e 100644 --- a/src/solvers/td3.ml +++ b/src/solvers/td3.ml @@ -977,6 +977,7 @@ module WP = filter_vs_hm infl; filter_vs_hm side_infl; filter_vs_hm side_dep; + filter_vs_hm dep; VH.filteri_inplace (fun x w -> if VH.mem reachable x then ( @@ -993,7 +994,7 @@ module WP = end in - (* postsolver also populates side_dep and side_infl *) + (* postsolver also populates side_dep, side_infl, and dep *) let module SideInfl: PostSolver.S with module S = S and module VH = HM and module VS = VS= struct include PostSolver.Unit (S) (HM) (VS) @@ -1006,6 +1007,28 @@ module WP = end in + let reachable_and_superstable = + if incr_verify then + (* Perform reachability on whole constraint system, but cheaply by using logged dependencies *) + (* This only works if the other reachability has been performed before, so dependencies created only during postsolve are recorded *) + let reachable' = HM.create (HM.length rho) in + let rechable_and_superstable = HM.create (HM.length rho) in + let rec one_var' x = + if (not (HM.mem reachable' x)) then ( + if HM.mem superstable x then HM.replace rechable_and_superstable x (); + HM.replace reachable' x (); + match HM.find_option dep x with + | Some vs -> VS.iter one_var' vs + | None -> () + ) + in + (Stats.time "cheap_full_reach" (List.iter one_var')) vs; + + rechable_and_superstable (* consider superstable reached if it is still reachable: stop recursion (evaluation) and keep from being pruned *) + else + HM.create 0 (* doesn't matter, not used *) + in + (* restart write-only *) HM.iter (fun x w -> HM.iter (fun y d -> @@ -1014,20 +1037,15 @@ module WP = ) rho_write; if incr_verify then ( - HM.filteri_inplace (fun x _ -> HM.mem superstable x) var_messages; - HM.filteri_inplace (fun x _ -> HM.mem superstable x) rho_write + HM.filteri_inplace (fun x _ -> HM.mem reachable_and_superstable x) var_messages; + HM.filteri_inplace (fun x _ -> HM.mem reachable_and_superstable x) rho_write ) else ( HM.clear var_messages; HM.clear rho_write ); - let init_reachable = - if incr_verify then - HM.copy superstable (* consider superstable reached: stop recursion (evaluation) and keep from being pruned *) - else - HM.create 0 (* doesn't matter, not used *) - in + let init_reachable = reachable_and_superstable in let module IncrWarn: PostSolver.S with module S = S and module VH = HM and module VS = VS = struct @@ -1047,7 +1065,7 @@ module WP = (* replay superstable messages from unknowns that are still reachable *) if incr_verify then ( HM.iter (fun (l:S.v) m -> - if HM.mem reachable l then Messages.add m + Messages.add m ) var_messages; ); @@ -1085,14 +1103,13 @@ module WP = (* retrigger superstable side writes from unknowns that are still reachable *) if incr_verify then ( HM.iter (fun x w -> - if HM.mem reachable x then - HM.iter (fun y d -> - let old_d = try HM.find rho y with Not_found -> S.Dom.bot () in - (* ignore (Pretty.printf "rho_write retrigger %a %a %a %a\n" S.Var.pretty_trace x S.Var.pretty_trace y S.Dom.pretty old_d S.Dom.pretty d); *) - HM.replace rho y (S.Dom.join old_d d); - HM.replace init_reachable y (); - HM.replace stable y (); (* make stable just in case, so following incremental load would have in superstable *) - ) w + HM.iter (fun y d -> + let old_d = try HM.find rho y with Not_found -> S.Dom.bot () in + (* ignore (Pretty.printf "rho_write retrigger %a %a %a %a\n" S.Var.pretty_trace x S.Var.pretty_trace y S.Dom.pretty old_d S.Dom.pretty d); *) + HM.replace rho y (S.Dom.join old_d d); + HM.replace init_reachable y (); + HM.replace stable y (); (* make stable just in case, so following incremental load would have in superstable *) + ) w ) rho_write ) From c1933db3373d623a7d5c80389a571ee9367eb911 Mon Sep 17 00:00:00 2001 From: Michael Schwarz Date: Mon, 2 May 2022 10:37:05 +0200 Subject: [PATCH 314/402] Undo unneeded modifications --- src/framework/constraints.ml | 5 ++-- src/solvers/postSolver.ml | 49 ++++++++++++++++-------------------- src/solvers/td3.ml | 20 +++++++-------- 3 files changed, 33 insertions(+), 41 deletions(-) diff --git a/src/framework/constraints.ml b/src/framework/constraints.ml index 6d00d1935d..cf85bcb73c 100644 --- a/src/framework/constraints.ml +++ b/src/framework/constraints.ml @@ -797,14 +797,13 @@ module EqIncrSolverFromEqSolver (Sol: GenericEqBoxSolver): GenericEqBoxIncrSolve functor (Arg: IncrSolverArg) (S: EqConstrSys) (VH: Hashtbl.S with type key = S.v) -> struct module Sol = Sol (S) (VH) - module VS = BatSet.Make(S.Var) - module Post = PostSolver.MakeList (PostSolver.ListArgFromStdArg (S) (VH) (VS) (Arg)) + module Post = PostSolver.MakeList (PostSolver.ListArgFromStdArg (S) (VH) (Arg)) type marshal = unit let solve box xs vs = let vh = Sol.solve box xs vs in - Post.post xs vs vh None; + Post.post xs vs vh; (vh, ()) end diff --git a/src/solvers/postSolver.ml b/src/solvers/postSolver.ml index f56c61e4b5..fa763a3c3e 100644 --- a/src/solvers/postSolver.ml +++ b/src/solvers/postSolver.ml @@ -7,7 +7,6 @@ module type S = sig module S: EqConstrSys module VH: Hashtbl.S with type key = S.v - module VS: BatSet.S with type elt = S.v val init: unit -> unit val one_side: vh:S.Dom.t VH.t -> x:S.v -> y:S.v -> d:S.Dom.t -> unit @@ -17,16 +16,15 @@ end (** Functorial postsolver for any system. *) module type F = - functor (S: EqConstrSys) (VH: Hashtbl.S with type key = S.v) (VS: BatSet.S with type elt = S.v) -> - S with module S = S and module VH = VH and module VS = VS + functor (S: EqConstrSys) (VH: Hashtbl.S with type key = S.v) -> + S with module S = S and module VH = VH (** Base implementation for postsolver. *) module Unit: F = - functor (S: EqConstrSys) (VH: Hashtbl.S with type key = S.v) (VS: BatSet.S with type elt = S.v) -> + functor (S: EqConstrSys) (VH: Hashtbl.S with type key = S.v) -> struct module S = S module VH = VH - module VS = VS let init () = () let one_side ~vh ~x ~y ~d = () let one_constraint ~vh ~x ~rhs = () @@ -34,11 +32,10 @@ module Unit: F = end (** Sequential composition of two postsolvers. *) -module Compose (PS1: S) (PS2: S with module S = PS1.S and module VH = PS1.VH and module VS = PS1.VS): S with module S = PS1.S and module VH = PS1.VH and module VS = PS1.VS = +module Compose (PS1: S) (PS2: S with module S = PS1.S and module VH = PS1.VH): S with module S = PS1.S and module VH = PS1.VH = struct module S = PS1.S module VH = PS1.VH - module VS = PS1.VS let init () = PS1.init (); @@ -56,9 +53,9 @@ end (** Postsolver for pruning solution using reachability. *) module Prune: F = - functor (S: EqConstrSys) (VH: Hashtbl.S with type key = S.v) (VS: BatSet.S with type elt = S.v) -> + functor (S: EqConstrSys) (VH: Hashtbl.S with type key = S.v) -> struct - include Unit (S) (VH) (VS) + include Unit (S) (VH) let finalize ~vh ~reachable = if get_bool "dbg.debug" then @@ -71,9 +68,9 @@ module Prune: F = (** Postsolver for verifying solution in demand-driven fashion. *) module Verify: F = - functor (S: EqConstrSys) (VH: Hashtbl.S with type key = S.v) (VS: BatSet.S with type elt = S.v) -> + functor (S: EqConstrSys) (VH: Hashtbl.S with type key = S.v) -> struct - include Unit (S) (VH) (VS) + include Unit (S) (VH) let init () = Goblintutil.verified := Some true @@ -101,9 +98,9 @@ module Verify: F = (** Postsolver for enabling messages (warnings) output. *) module Warn: F = - functor (S: EqConstrSys) (VH: Hashtbl.S with type key = S.v) (VS: BatSet.S with type elt = S.v) -> + functor (S: EqConstrSys) (VH: Hashtbl.S with type key = S.v) -> struct - include Unit (S) (VH) (VS) + include Unit (S) (VH) let old_should_warn = ref None @@ -117,9 +114,9 @@ module Warn: F = (** Postsolver for save_run option. *) module SaveRun: F = - functor (S: EqConstrSys) (VH: Hashtbl.S with type key = S.v) (VS: BatSet.S with type elt = S.v) -> + functor (S: EqConstrSys) (VH: Hashtbl.S with type key = S.v) -> struct - include Unit (S) (VH) (VS) + include Unit (S) (VH) let finalize ~vh ~reachable = (* copied from Control.solve_and_postprocess *) @@ -175,10 +172,9 @@ end module MakeIncr (PS: IncrS) = struct module S = PS.S - module VS = PS.VS module VH = PS.VH - let post xs vs vh dep = + let post xs vs vh = if get_bool "dbg.verbose" then print_endline "Postsolving\n"; @@ -220,8 +216,8 @@ struct PS.finalize ~vh ~reachable:reachable; Goblintutil.postsolving := false - let post xs vs vh dep = - Stats.time "postsolver" (post xs vs vh) dep + let post xs vs vh = + Stats.time "postsolver" (post xs vs) vh end (** List of postsolvers. *) @@ -230,9 +226,8 @@ sig (* Specify S and VH here to constrain all postsolvers to use the same. *) module S: EqConstrSys module VH: Hashtbl.S with type key = S.v - module VS: BatSet.S with type elt = S.v (* Auxiliary module type because first-class module types cannot contain module constraints. *) - module type M = S with module S = S and module VH = VH and module VS = VS + module type M = S with module S = S and module VH = VH val postsolvers: (module M) list end @@ -251,7 +246,6 @@ module MakeIncrList (Arg: MakeIncrListArg) = struct module S = Arg.S module VH = Arg.VH - module VS = Arg.VS let postsolver_opt: (module Arg.M) option = match Arg.postsolvers with @@ -262,7 +256,7 @@ struct in Some (List.reduce compose postsolvers) - let post xs vs vh dep = + let post xs vs vh = match postsolver_opt with | None -> () | Some (module PS) -> @@ -273,7 +267,7 @@ struct end in let module M = MakeIncr (IncrPS) in - M.post xs vs vh dep + M.post xs vs vh end (** Make complete (non-incremental) postsolving function from list of postsolvers. @@ -298,14 +292,13 @@ sig end (** List of standard postsolvers. *) -module ListArgFromStdArg (S: EqConstrSys) (VH: Hashtbl.S with type key = S.v) (VS: BatSet.S with type elt = S.v) (Arg: MakeStdArg): MakeListArg with module S = S and module VH = VH and module VS = VS = +module ListArgFromStdArg (S: EqConstrSys) (VH: Hashtbl.S with type key = S.v) (Arg: MakeStdArg): MakeListArg with module S = S and module VH = VH = struct open Arg module S = S module VH = VH - module VS = VS - module type M = S with module S = S and module VH = VH and module VS = VS + module type M = S with module S = S and module VH = VH let postsolvers: (bool * (module F)) list = [ (should_prune, (module Prune)); @@ -318,5 +311,5 @@ struct postsolvers |> List.filter fst |> List.map snd - |> List.map (fun (module F: F) -> (module F (S) (VH) (VS): M)) + |> List.map (fun (module F: F) -> (module F (S) (VH): M)) end diff --git a/src/solvers/td3.ml b/src/solvers/td3.ml index d56e8e7a4e..fa1206b089 100644 --- a/src/solvers/td3.ml +++ b/src/solvers/td3.ml @@ -956,9 +956,9 @@ module WP = (* Prune other data structures than rho with reachable. These matter for the incremental data. *) - let module IncrPrune: PostSolver.S with module S = S and module VH = HM and module VS = VS = + let module IncrPrune: PostSolver.S with module S = S and module VH = HM = struct - include PostSolver.Unit (S) (HM) (VS) + include PostSolver.Unit (S) (HM) let finalize ~vh ~reachable = VH.filteri_inplace (fun x _ -> @@ -995,9 +995,9 @@ module WP = in (* postsolver also populates side_dep, side_infl, and dep *) - let module SideInfl: PostSolver.S with module S = S and module VH = HM and module VS = VS= + let module SideInfl: PostSolver.S with module S = S and module VH = HM = struct - include PostSolver.Unit (S) (HM) (VS) + include PostSolver.Unit (S) (HM) let one_side ~vh ~x ~y ~d = (* Also record side-effects caused by post-solver *) @@ -1047,9 +1047,9 @@ module WP = let init_reachable = reachable_and_superstable in - let module IncrWarn: PostSolver.S with module S = S and module VH = HM and module VS = VS = + let module IncrWarn: PostSolver.S with module S = S and module VH = HM = struct - include PostSolver.Warn (S) (HM) (VS) + include PostSolver.Warn (S) (HM) let init () = init (); (* enable warning like standard Warn *) @@ -1078,9 +1078,9 @@ module WP = (** Incremental write-only side effect restart handling: retriggers superstable ones (after restarting above) and collects new (non-superstable) ones. *) - let module IncrWrite: PostSolver.S with module S = S and module VH = HM and module VS = VS = + let module IncrWrite: PostSolver.S with module S = S and module VH = HM = struct - include PostSolver.Unit (S) (HM) (VS) + include PostSolver.Unit (S) (HM) let init () = () @@ -1123,7 +1123,7 @@ module WP = include Arg let should_warn = false (* disable standard Warn in favor of IncrWarn *) end - include PostSolver.ListArgFromStdArg (S) (HM) (VS) (Arg) + include PostSolver.ListArgFromStdArg (S) (HM) (Arg) let postsolvers = (module IncrPrune: M) :: (module SideInfl: M) :: (module IncrWrite: M) :: (module IncrWarn: M) :: postsolvers @@ -1137,7 +1137,7 @@ module WP = let module Post = PostSolver.MakeIncrList (MakeIncrListArg) in - Post.post st vs rho (Some dep); + Post.post st vs rho; print_data data "Data after postsolve"; From 5850d936bac101e358cbe8b0127c231829d1f295 Mon Sep 17 00:00:00 2001 From: Michael Schwarz Date: Mon, 2 May 2022 10:40:48 +0200 Subject: [PATCH 315/402] minimize diff --- src/solvers/postSolver.ml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/solvers/postSolver.ml b/src/solvers/postSolver.ml index fa763a3c3e..c2ef566756 100644 --- a/src/solvers/postSolver.ml +++ b/src/solvers/postSolver.ml @@ -98,7 +98,7 @@ module Verify: F = (** Postsolver for enabling messages (warnings) output. *) module Warn: F = - functor (S: EqConstrSys) (VH: Hashtbl.S with type key = S.v) -> + functor (S: EqConstrSys) (VH: Hashtbl.S with type key = S.v) -> struct include Unit (S) (VH) @@ -114,7 +114,7 @@ module Warn: F = (** Postsolver for save_run option. *) module SaveRun: F = - functor (S: EqConstrSys) (VH: Hashtbl.S with type key = S.v) -> + functor (S: EqConstrSys) (VH: Hashtbl.S with type key = S.v) -> struct include Unit (S) (VH) @@ -213,7 +213,7 @@ struct in (Stats.time "potentially_incremental_reach" (List.iter one_var)) vs; - PS.finalize ~vh ~reachable:reachable; + PS.finalize ~vh ~reachable; Goblintutil.postsolving := false let post xs vs vh = From 83ec1a19d1c86edce2310599dd02d8e06f4b8893 Mon Sep 17 00:00:00 2001 From: Michael Schwarz Date: Mon, 2 May 2022 11:19:10 +0200 Subject: [PATCH 316/402] Move incr_verify specific changes back --- src/solvers/td3.ml | 43 ++++++++++++++++++++----------------------- 1 file changed, 20 insertions(+), 23 deletions(-) diff --git a/src/solvers/td3.ml b/src/solvers/td3.ml index fa1206b089..7211e06d30 100644 --- a/src/solvers/td3.ml +++ b/src/solvers/td3.ml @@ -1054,6 +1054,13 @@ module WP = let init () = init (); (* enable warning like standard Warn *) + (* replay superstable messages from unknowns that are still reachable *) + if incr_verify then ( + HM.iter (fun (l:S.v) m -> + Messages.add m + ) var_messages; + ); + (* hook to collect new messages *) Messages.Table.add_hook := (fun m -> match !current_var with @@ -1062,13 +1069,6 @@ module WP = ) let finalize ~vh ~reachable = - (* replay superstable messages from unknowns that are still reachable *) - if incr_verify then ( - HM.iter (fun (l:S.v) m -> - Messages.add m - ) var_messages; - ); - finalize ~vh ~reachable; (* disable warning like standard Warn *) (* unhook to avoid accidental var_messages modifications *) @@ -1082,7 +1082,19 @@ module WP = struct include PostSolver.Unit (S) (HM) - let init () = () + let init () = + (* retrigger superstable side writes from unknowns that are still reachable *) + if incr_verify then ( + HM.iter (fun x w -> + HM.iter (fun y d -> + let old_d = try HM.find rho y with Not_found -> S.Dom.bot () in + (* ignore (Pretty.printf "rho_write retrigger %a %a %a %a\n" S.Var.pretty_trace x S.Var.pretty_trace y S.Dom.pretty old_d S.Dom.pretty d); *) + HM.replace rho y (S.Dom.join old_d d); + HM.replace init_reachable y (); + HM.replace stable y (); (* make stable just in case, so following incremental load would have in superstable *) + ) w + ) rho_write + ) let one_side ~vh ~x ~y ~d = if S.Var.is_write_only y then ( @@ -1098,21 +1110,6 @@ module WP = in VH.add w y d (* intentional add *) ) - - let finalize ~vh ~reachable = - (* retrigger superstable side writes from unknowns that are still reachable *) - if incr_verify then ( - HM.iter (fun x w -> - HM.iter (fun y d -> - let old_d = try HM.find rho y with Not_found -> S.Dom.bot () in - (* ignore (Pretty.printf "rho_write retrigger %a %a %a %a\n" S.Var.pretty_trace x S.Var.pretty_trace y S.Dom.pretty old_d S.Dom.pretty d); *) - HM.replace rho y (S.Dom.join old_d d); - HM.replace init_reachable y (); - HM.replace stable y (); (* make stable just in case, so following incremental load would have in superstable *) - ) w - ) rho_write - ) - end in From ddda0939e4620d904de155a9d531ea8db41ea993 Mon Sep 17 00:00:00 2001 From: Michael Schwarz Date: Mon, 2 May 2022 11:20:26 +0200 Subject: [PATCH 317/402] Cleanup --- src/solvers/td3.ml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/solvers/td3.ml b/src/solvers/td3.ml index 7211e06d30..3614ac0e41 100644 --- a/src/solvers/td3.ml +++ b/src/solvers/td3.ml @@ -1056,7 +1056,7 @@ module WP = (* replay superstable messages from unknowns that are still reachable *) if incr_verify then ( - HM.iter (fun (l:S.v) m -> + HM.iter (fun _ m -> Messages.add m ) var_messages; ); From f45f19427b3e1745dfcab9a4f9daef962a52fb43 Mon Sep 17 00:00:00 2001 From: Michael Schwarz Date: Mon, 2 May 2022 11:25:00 +0200 Subject: [PATCH 318/402] Cleanup --- src/solvers/postSolver.ml | 2 +- src/solvers/td3.ml | 4 +--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/solvers/postSolver.ml b/src/solvers/postSolver.ml index c2ef566756..776a1719ed 100644 --- a/src/solvers/postSolver.ml +++ b/src/solvers/postSolver.ml @@ -211,7 +211,7 @@ struct if M.tracing then M.trace "postsolver" "one_constraint %a %a\n" S.Var.pretty_trace x S.Dom.pretty rhs; PS.one_constraint ~vh ~x ~rhs in - (Stats.time "potentially_incremental_reach" (List.iter one_var)) vs; + (Stats.time "postsolver_iter" (List.iter one_var)) vs; PS.finalize ~vh ~reachable; Goblintutil.postsolving := false diff --git a/src/solvers/td3.ml b/src/solvers/td3.ml index 3614ac0e41..01df2ad9e7 100644 --- a/src/solvers/td3.ml +++ b/src/solvers/td3.ml @@ -1017,9 +1017,7 @@ module WP = if (not (HM.mem reachable' x)) then ( if HM.mem superstable x then HM.replace rechable_and_superstable x (); HM.replace reachable' x (); - match HM.find_option dep x with - | Some vs -> VS.iter one_var' vs - | None -> () + Option.may (VS.iter one_var') (HM.find_option dep x) ) in (Stats.time "cheap_full_reach" (List.iter one_var')) vs; From 9940dea3cafc1f967635e85583f26173d5925d8a Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Fri, 18 Mar 2022 10:50:44 +0200 Subject: [PATCH 319/402] Add incremental test where race in removed call remains --- .../13-restart-write/05-race-call-remove.c | 20 +++++++++++++++ .../13-restart-write/05-race-call-remove.json | 14 +++++++++++ .../05-race-call-remove.patch | 25 +++++++++++++++++++ 3 files changed, 59 insertions(+) create mode 100644 tests/incremental/13-restart-write/05-race-call-remove.c create mode 100644 tests/incremental/13-restart-write/05-race-call-remove.json create mode 100644 tests/incremental/13-restart-write/05-race-call-remove.patch diff --git a/tests/incremental/13-restart-write/05-race-call-remove.c b/tests/incremental/13-restart-write/05-race-call-remove.c new file mode 100644 index 0000000000..cf9f5c7133 --- /dev/null +++ b/tests/incremental/13-restart-write/05-race-call-remove.c @@ -0,0 +1,20 @@ +#include +#include + +int g; + +void *t_fun(void *arg) { + g++; // RACE! + return NULL; +} + +void foo() { + g++; // RACE! +} + +int main() { + pthread_t id; + pthread_create(&id, NULL, t_fun, NULL); + foo(); + return 0; +} \ No newline at end of file diff --git a/tests/incremental/13-restart-write/05-race-call-remove.json b/tests/incremental/13-restart-write/05-race-call-remove.json new file mode 100644 index 0000000000..f65fca9568 --- /dev/null +++ b/tests/incremental/13-restart-write/05-race-call-remove.json @@ -0,0 +1,14 @@ +{ + "incremental": { + "restart": { + "sided": { + "enabled": false + } + } + }, + "ana": { + "thread": { + "include-node": false + } + } +} \ No newline at end of file diff --git a/tests/incremental/13-restart-write/05-race-call-remove.patch b/tests/incremental/13-restart-write/05-race-call-remove.patch new file mode 100644 index 0000000000..212df350cc --- /dev/null +++ b/tests/incremental/13-restart-write/05-race-call-remove.patch @@ -0,0 +1,25 @@ +diff --git tests/incremental/13-restart-write/05-race-call-remove.c tests/incremental/13-restart-write/05-race-call-remove.c +index cf9f5c713..20e09db1a 100644 +--- tests/incremental/13-restart-write/05-race-call-remove.c ++++ tests/incremental/13-restart-write/05-race-call-remove.c +@@ -4,17 +4,16 @@ + int g; + + void *t_fun(void *arg) { +- g++; // RACE! ++ g++; // NORACE (unique thread) + return NULL; + } + + void foo() { +- g++; // RACE! ++ g++; // NORACE + } + + int main() { + pthread_t id; + pthread_create(&id, NULL, t_fun, NULL); +- foo(); + return 0; + } +\ No newline at end of file From da4564d732107e3c9a02a9b64cc96cb5189710c0 Mon Sep 17 00:00:00 2001 From: Michael Schwarz Date: Mon, 2 May 2022 12:05:46 +0200 Subject: [PATCH 320/402] Record less in `dep`, do not clear `side_infl` and `side_dep` --- src/solvers/td3.ml | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/src/solvers/td3.ml b/src/solvers/td3.ml index 01df2ad9e7..ce0829bf1f 100644 --- a/src/solvers/td3.ml +++ b/src/solvers/td3.ml @@ -156,7 +156,7 @@ module WP = let abort_verify = GobConfig.get_bool "solvers.td3.abort-verify" in let prev_dep_vals = HM.create 10 in - (* Tracks dependencies between an unknown and the things it depends on AND has side-effects to *) + (* Tracks dependencies between an unknown and the things it depends on *) let dep = data.dep in let () = print_solver_stats := fun () -> @@ -189,11 +189,7 @@ module WP = HM.replace infl y (VS.add x (try HM.find infl y with Not_found -> VS.empty)); HM.replace dep x (VS.add y (HM.find_default dep x VS.empty)); in - let add_sides y x = - (* dep records also the things an unknown has side-effects on *) - HM.replace dep x (VS.add y (HM.find_default dep x VS.empty)); - HM.replace sides y (VS.add x (try HM.find sides y with Not_found -> VS.empty)) in - + let add_sides y x = HM.replace sides y (VS.add x (try HM.find sides y with Not_found -> VS.empty)) in let destabilize_ref: (?front:bool -> S.v -> unit) ref = ref (fun ?front _ -> failwith "no destabilize yet") in let destabilize x = !destabilize_ref x in (* must be eta-expanded to use changed destabilize_ref *) @@ -862,10 +858,6 @@ module WP = print_endline "Final solve..." ); - - (* reachability will populate these tables for incremental global restarting *) - HM.clear side_dep; - HM.clear side_infl; ) else ( List.iter set_start st; ); @@ -1001,7 +993,6 @@ module WP = let one_side ~vh ~x ~y ~d = (* Also record side-effects caused by post-solver *) - HM.replace dep x (VS.add y (HM.find_default dep x VS.empty)); HM.replace side_dep y (VS.add x (try HM.find side_dep y with Not_found -> VS.empty)); HM.replace side_infl x (VS.add y (try HM.find side_infl x with Not_found -> VS.empty)); end @@ -1017,7 +1008,8 @@ module WP = if (not (HM.mem reachable' x)) then ( if HM.mem superstable x then HM.replace rechable_and_superstable x (); HM.replace reachable' x (); - Option.may (VS.iter one_var') (HM.find_option dep x) + Option.may (VS.iter one_var') (HM.find_option dep x); + Option.may (VS.iter one_var') (HM.find_option side_infl x) ) in (Stats.time "cheap_full_reach" (List.iter one_var')) vs; From 8b7d4d352b207644150dd0c421ca15abcd3b98fe Mon Sep 17 00:00:00 2001 From: Michael Schwarz Date: Mon, 2 May 2022 15:29:48 +0200 Subject: [PATCH 321/402] Print same solver stats consistently --- src/solvers/td3.ml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/solvers/td3.ml b/src/solvers/td3.ml index ce0829bf1f..86aa9d2aa2 100644 --- a/src/solvers/td3.ml +++ b/src/solvers/td3.ml @@ -160,9 +160,9 @@ module WP = let dep = data.dep in let () = print_solver_stats := fun () -> - Printf.printf "|rho|=%d\n|called|=%d\n|stable|=%d\n|infl|=%d\n|wpoint|=%d\n|side_dep|=%d\n|side_infl|=%d\n" - (HM.length rho) (HM.length called) (HM.length stable) (HM.length infl) (HM.length wpoint) (HM.length side_dep) (HM.length side_infl); - print_context_stats rho + Printf.printf "|rho|=%d\n|called|=%d\n|stable|=%d\n|infl|=%d\n|wpoint|=%d\n|side_dep|=%d\n|side_infl|=%d\n|dep|=%d\n" + (HM.length rho) (HM.length called) (HM.length stable) (HM.length infl) (HM.length wpoint) (HM.length side_dep) (HM.length side_infl) (HM.length dep); + print_context_stats rho in if GobConfig.get_bool "incremental.load" then ( From 50fed60cb95d25ab542b30e5a029ea5779ffc91d Mon Sep 17 00:00:00 2001 From: Michael Schwarz Date: Mon, 2 May 2022 15:30:56 +0200 Subject: [PATCH 322/402] Typo --- src/solvers/td3.ml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/solvers/td3.ml b/src/solvers/td3.ml index 86aa9d2aa2..3f038f9787 100644 --- a/src/solvers/td3.ml +++ b/src/solvers/td3.ml @@ -1003,10 +1003,10 @@ module WP = (* Perform reachability on whole constraint system, but cheaply by using logged dependencies *) (* This only works if the other reachability has been performed before, so dependencies created only during postsolve are recorded *) let reachable' = HM.create (HM.length rho) in - let rechable_and_superstable = HM.create (HM.length rho) in + let reachable_and_superstable = HM.create (HM.length rho) in let rec one_var' x = if (not (HM.mem reachable' x)) then ( - if HM.mem superstable x then HM.replace rechable_and_superstable x (); + if HM.mem superstable x then HM.replace reachable_and_superstable x (); HM.replace reachable' x (); Option.may (VS.iter one_var') (HM.find_option dep x); Option.may (VS.iter one_var') (HM.find_option side_infl x) @@ -1014,7 +1014,7 @@ module WP = in (Stats.time "cheap_full_reach" (List.iter one_var')) vs; - rechable_and_superstable (* consider superstable reached if it is still reachable: stop recursion (evaluation) and keep from being pruned *) + reachable_and_superstable (* consider superstable reached if it is still reachable: stop recursion (evaluation) and keep from being pruned *) else HM.create 0 (* doesn't matter, not used *) in From d6226110ea02674418534afea57c1f1fcdb02756 Mon Sep 17 00:00:00 2001 From: Michael Schwarz Date: Tue, 3 May 2022 08:49:04 +0200 Subject: [PATCH 323/402] Comment about resetting side_infl --- src/solvers/td3.ml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/solvers/td3.ml b/src/solvers/td3.ml index 8d050ea26a..5afd32d275 100644 --- a/src/solvers/td3.ml +++ b/src/solvers/td3.ml @@ -1005,6 +1005,8 @@ module WP = struct include PostSolver.Unit (S) (HM) + (* TODO: We should be able to reset side_infl before executing the RHS, as all relevant side-effects should happen here again *) + (* However, this currently breaks some tests https://github.com/goblint/analyzer/pull/713#issuecomment-1114764937 *) let one_side ~vh ~x ~y ~d = (* Also record side-effects caused by post-solver *) HM.replace side_dep y (VS.add x (try HM.find side_dep y with Not_found -> VS.empty)); From 3f96c77afcf004ee0ac42aac13116214ff7ab4da Mon Sep 17 00:00:00 2001 From: Michael Schwarz Date: Tue, 3 May 2022 09:09:43 +0200 Subject: [PATCH 324/402] Rename incremental.verify -> incremental.postsolver.enabled --- src/solvers/td3.ml | 2 +- src/util/options.schema.json | 23 +++++++++++++++---- tests/incremental/00-basic/09-unreach.json | 4 +++- tests/incremental/00-basic/10-reach.json | 4 +++- .../01-force-reanalyze/01-int-reluctant.json | 4 +++- .../02-reluctant-int-annotation.json | 4 +++- .../03-reluctant-int-annotation-dyn.json | 4 +++- 7 files changed, 34 insertions(+), 11 deletions(-) diff --git a/src/solvers/td3.ml b/src/solvers/td3.ml index 5afd32d275..4ce57d33bf 100644 --- a/src/solvers/td3.ml +++ b/src/solvers/td3.ml @@ -140,7 +140,7 @@ module WP = let restart_once = GobConfig.get_bool "solvers.td3.restart.wpoint.once" in let restarted_wpoint = HM.create 10 in - let incr_verify = GobConfig.get_bool "incremental.verify" in + let incr_verify = GobConfig.get_bool "incremental.postsolver.enabled" in (* In incremental load, initially stable nodes, which are never destabilized. These don't have to be re-verified and warnings can be reused. *) let superstable = HM.copy stable in diff --git a/src/util/options.schema.json b/src/util/options.schema.json index 0ce78852be..e0fa83bb5b 100644 --- a/src/util/options.schema.json +++ b/src/util/options.schema.json @@ -1053,11 +1053,24 @@ }, "additionalProperties": false }, - "verify": { - "title": "incremental.verify", - "description": "TODO", - "type": "boolean", - "default": true + "postsolver": { + "title": "incremental.postsolver", + "type" : "object", + "properties": { + "enabled": { + "title": "incremental.postsolver.enabled", + "description": "Use incremental postsolver", + "type": "boolean", + "default": true + }, + "superstable-reached" : { + "title": "incremental.postsolver.superstable-reached", + "description": "Consider superstable set reached", + "type": "boolean", + "default": false + } + }, + "additionalProperties": false } }, "additionalProperties": false diff --git a/tests/incremental/00-basic/09-unreach.json b/tests/incremental/00-basic/09-unreach.json index aee1ae335b..c1e5e17542 100644 --- a/tests/incremental/00-basic/09-unreach.json +++ b/tests/incremental/00-basic/09-unreach.json @@ -3,6 +3,8 @@ "debug": true }, "incremental" : { - "verify": true + "postsolver": { + "enabled": true + } } } diff --git a/tests/incremental/00-basic/10-reach.json b/tests/incremental/00-basic/10-reach.json index aee1ae335b..c1e5e17542 100644 --- a/tests/incremental/00-basic/10-reach.json +++ b/tests/incremental/00-basic/10-reach.json @@ -3,6 +3,8 @@ "debug": true }, "incremental" : { - "verify": true + "postsolver": { + "enabled": true + } } } diff --git a/tests/incremental/01-force-reanalyze/01-int-reluctant.json b/tests/incremental/01-force-reanalyze/01-int-reluctant.json index ab2c9fff31..6fe26c0b7e 100644 --- a/tests/incremental/01-force-reanalyze/01-int-reluctant.json +++ b/tests/incremental/01-force-reanalyze/01-int-reluctant.json @@ -17,6 +17,8 @@ "reluctant" : { "on": true }, - "verify": false + "postsolver": { + "enabled": false + } } } diff --git a/tests/incremental/03-precision-annotation/02-reluctant-int-annotation.json b/tests/incremental/03-precision-annotation/02-reluctant-int-annotation.json index 14f2bac8c0..ff13de39d1 100644 --- a/tests/incremental/03-precision-annotation/02-reluctant-int-annotation.json +++ b/tests/incremental/03-precision-annotation/02-reluctant-int-annotation.json @@ -14,6 +14,8 @@ "reluctant": { "on": true }, - "verify": false + "postsolver": { + "enabled": false + } } } diff --git a/tests/incremental/03-precision-annotation/03-reluctant-int-annotation-dyn.json b/tests/incremental/03-precision-annotation/03-reluctant-int-annotation-dyn.json index 14f2bac8c0..ff13de39d1 100644 --- a/tests/incremental/03-precision-annotation/03-reluctant-int-annotation-dyn.json +++ b/tests/incremental/03-precision-annotation/03-reluctant-int-annotation-dyn.json @@ -14,6 +14,8 @@ "reluctant": { "on": true }, - "verify": false + "postsolver": { + "enabled": false + } } } From 44f1efa8684e49b98fbd34fbb48e37f6a6150ba3 Mon Sep 17 00:00:00 2001 From: Michael Schwarz Date: Tue, 3 May 2022 09:21:11 +0200 Subject: [PATCH 325/402] Add option `incremental.postsolver.superstable-reached` --- src/solvers/td3.ml | 5 ++++- src/util/options.schema.json | 2 +- .../00-basic/11-unreach-reusesuper.c | 14 ++++++++++++++ .../00-basic/11-unreach-reusesuper.json | 11 +++++++++++ .../00-basic/11-unreach-reusesuper.patch | 17 +++++++++++++++++ 5 files changed, 47 insertions(+), 2 deletions(-) create mode 100644 tests/incremental/00-basic/11-unreach-reusesuper.c create mode 100644 tests/incremental/00-basic/11-unreach-reusesuper.json create mode 100644 tests/incremental/00-basic/11-unreach-reusesuper.patch diff --git a/src/solvers/td3.ml b/src/solvers/td3.ml index 4ce57d33bf..65ab0e8d42 100644 --- a/src/solvers/td3.ml +++ b/src/solvers/td3.ml @@ -141,6 +141,7 @@ module WP = let restarted_wpoint = HM.create 10 in let incr_verify = GobConfig.get_bool "incremental.postsolver.enabled" in + let consider_superstable_reached = GobConfig.get_bool "incremental.postsolver.superstable-reached" in (* In incremental load, initially stable nodes, which are never destabilized. These don't have to be re-verified and warnings can be reused. *) let superstable = HM.copy stable in @@ -1015,7 +1016,7 @@ module WP = in let reachable_and_superstable = - if incr_verify then + if incr_verify && not consider_superstable_reached then (* Perform reachability on whole constraint system, but cheaply by using logged dependencies *) (* This only works if the other reachability has been performed before, so dependencies created only during postsolve are recorded *) let reachable' = HM.create (HM.length rho) in @@ -1031,6 +1032,8 @@ module WP = (Stats.time "cheap_full_reach" (List.iter one_var')) (vs @ !reluctant_vs); reachable_and_superstable (* consider superstable reached if it is still reachable: stop recursion (evaluation) and keep from being pruned *) + else if incr_verify then + superstable else HM.create 0 (* doesn't matter, not used *) in diff --git a/src/util/options.schema.json b/src/util/options.schema.json index e0fa83bb5b..a15d2916d5 100644 --- a/src/util/options.schema.json +++ b/src/util/options.schema.json @@ -1065,7 +1065,7 @@ }, "superstable-reached" : { "title": "incremental.postsolver.superstable-reached", - "description": "Consider superstable set reached", + "description": "Consider superstable set reached, may be faster but can lead to spurious warnings", "type": "boolean", "default": false } diff --git a/tests/incremental/00-basic/11-unreach-reusesuper.c b/tests/incremental/00-basic/11-unreach-reusesuper.c new file mode 100644 index 0000000000..07e347a64b --- /dev/null +++ b/tests/incremental/00-basic/11-unreach-reusesuper.c @@ -0,0 +1,14 @@ +#include + +void foo() { + int x = 2; + assert(x == 3); //FAIL +} + +int main() { + int a = 1; + + foo(); + + return 0; +} diff --git a/tests/incremental/00-basic/11-unreach-reusesuper.json b/tests/incremental/00-basic/11-unreach-reusesuper.json new file mode 100644 index 0000000000..ef6bdab239 --- /dev/null +++ b/tests/incremental/00-basic/11-unreach-reusesuper.json @@ -0,0 +1,11 @@ +{ + "dbg": { + "debug": true + }, + "incremental" : { + "postsolver": { + "enabled": true, + "superstable-reached" : true + } + } +} diff --git a/tests/incremental/00-basic/11-unreach-reusesuper.patch b/tests/incremental/00-basic/11-unreach-reusesuper.patch new file mode 100644 index 0000000000..31f5e48712 --- /dev/null +++ b/tests/incremental/00-basic/11-unreach-reusesuper.patch @@ -0,0 +1,17 @@ +--- tests/incremental/00-basic/11-unreach-reusesuper.c ++++ tests/incremental/00-basic/11-unreach-reusesuper.c +@@ -2,13 +2,12 @@ + + void foo() { + int x = 2; +- assert(x == 3); //FAIL ++ assert(x == 3); //TODO (considered rechable without cheap from scratch re-analysis) + } + + int main() { + int a = 1; + +- foo(); + + return 0; + } From e117878de91cfb45ea1c9227f45d67c9be70bafd Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Fri, 18 Mar 2022 11:40:00 +0200 Subject: [PATCH 326/402] Add rho_write size to TD3 stats --- src/solvers/td3.ml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/solvers/td3.ml b/src/solvers/td3.ml index 65ab0e8d42..268ff10cdb 100644 --- a/src/solvers/td3.ml +++ b/src/solvers/td3.ml @@ -56,8 +56,8 @@ module WP = let print_data data str = if GobConfig.get_bool "dbg.verbose" then - Printf.printf "%s:\n|rho|=%d\n|stable|=%d\n|infl|=%d\n|wpoint|=%d\n|side_dep|=%d\n|side_infl|=%d\n|dep|=%d\n" - str (HM.length data.rho) (HM.length data.stable) (HM.length data.infl) (HM.length data.wpoint) (HM.length data.side_dep) (HM.length data.side_infl) (HM.length data.dep) + Printf.printf "%s:\n|rho|=%d\n|stable|=%d\n|infl|=%d\n|wpoint|=%d\n|side_dep|=%d\n|side_infl|=%d\n|rho_write|=%d\n|dep|=%d\n" + str (HM.length data.rho) (HM.length data.stable) (HM.length data.infl) (HM.length data.wpoint) (HM.length data.side_dep) (HM.length data.side_infl) (HM.length data.rho_write) (HM.length data.dep) let verify_data data = if GobConfig.get_bool "solvers.td3.verify" then ( @@ -161,8 +161,8 @@ module WP = let dep = data.dep in let () = print_solver_stats := fun () -> - Printf.printf "|rho|=%d\n|called|=%d\n|stable|=%d\n|infl|=%d\n|wpoint|=%d\n|side_dep|=%d\n|side_infl|=%d\n|dep|=%d\n" - (HM.length rho) (HM.length called) (HM.length stable) (HM.length infl) (HM.length wpoint) (HM.length side_dep) (HM.length side_infl) (HM.length dep); + Printf.printf "|rho|=%d\n|called|=%d\n|stable|=%d\n|infl|=%d\n|wpoint|=%d\n|side_dep|=%d\n|side_infl|=%d\n|rho_write|=%d\n|dep|=%d\n" + (HM.length rho) (HM.length called) (HM.length stable) (HM.length infl) (HM.length wpoint) (HM.length side_dep) (HM.length side_infl) (HM.length rho_write) (HM.length dep); print_context_stats rho in From 00dd10b4b263bb43c7d463ff014853a5be7cf487 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Fri, 18 Mar 2022 10:45:33 +0200 Subject: [PATCH 327/402] Add incremental test where race to old malloc node remains --- .../13-restart-write/04-malloc-node.c | 21 +++++++++++++++++++ .../13-restart-write/04-malloc-node.json | 14 +++++++++++++ .../13-restart-write/04-malloc-node.patch | 13 ++++++++++++ 3 files changed, 48 insertions(+) create mode 100644 tests/incremental/13-restart-write/04-malloc-node.c create mode 100644 tests/incremental/13-restart-write/04-malloc-node.json create mode 100644 tests/incremental/13-restart-write/04-malloc-node.patch diff --git a/tests/incremental/13-restart-write/04-malloc-node.c b/tests/incremental/13-restart-write/04-malloc-node.c new file mode 100644 index 0000000000..87bbc0f141 --- /dev/null +++ b/tests/incremental/13-restart-write/04-malloc-node.c @@ -0,0 +1,21 @@ +#include +#include + +void *t_fun(void *arg) { + int *iarg = (int*) arg; + *iarg = 1; + return NULL; +} + +int main() { + pthread_t id; + int *iarg; + + for (int i = 0; i < 10; i++) { + iarg = malloc(sizeof(int)); + *iarg = 0; + pthread_create(&id, NULL, t_fun, (void*) iarg); + } + + return 0; +} \ No newline at end of file diff --git a/tests/incremental/13-restart-write/04-malloc-node.json b/tests/incremental/13-restart-write/04-malloc-node.json new file mode 100644 index 0000000000..f65fca9568 --- /dev/null +++ b/tests/incremental/13-restart-write/04-malloc-node.json @@ -0,0 +1,14 @@ +{ + "incremental": { + "restart": { + "sided": { + "enabled": false + } + } + }, + "ana": { + "thread": { + "include-node": false + } + } +} \ No newline at end of file diff --git a/tests/incremental/13-restart-write/04-malloc-node.patch b/tests/incremental/13-restart-write/04-malloc-node.patch new file mode 100644 index 0000000000..e8eedc4bb0 --- /dev/null +++ b/tests/incremental/13-restart-write/04-malloc-node.patch @@ -0,0 +1,13 @@ +diff --git tests/incremental/13-restart-write/04-malloc-node.c tests/incremental/13-restart-write/04-malloc-node.c +index 87bbc0f14..3cd6dc5c7 100644 +--- tests/incremental/13-restart-write/04-malloc-node.c ++++ tests/incremental/13-restart-write/04-malloc-node.c +@@ -11,6 +11,8 @@ int main() { + pthread_t id; + int *iarg; + ++ assert(1); ++ + for (int i = 0; i < 10; i++) { + iarg = malloc(sizeof(int)); + *iarg = 0; From ed2ad3a42676c204df897f2a4986df59f931ed46 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Tue, 3 May 2022 11:29:54 +0300 Subject: [PATCH 328/402] Annotate incremental 13-restart-write/04-malloc-node for races --- .../13-restart-write/04-malloc-node.c | 4 ++-- .../13-restart-write/04-malloc-node.json | 4 ++++ .../13-restart-write/04-malloc-node.patch | 18 ++++++++++++------ 3 files changed, 18 insertions(+), 8 deletions(-) diff --git a/tests/incremental/13-restart-write/04-malloc-node.c b/tests/incremental/13-restart-write/04-malloc-node.c index 87bbc0f141..2e61e5429f 100644 --- a/tests/incremental/13-restart-write/04-malloc-node.c +++ b/tests/incremental/13-restart-write/04-malloc-node.c @@ -3,7 +3,7 @@ void *t_fun(void *arg) { int *iarg = (int*) arg; - *iarg = 1; + *iarg = 1; // RACE (without mallocFresh) return NULL; } @@ -13,7 +13,7 @@ int main() { for (int i = 0; i < 10; i++) { iarg = malloc(sizeof(int)); - *iarg = 0; + *iarg = 0; // RACE (without mallocFresh) pthread_create(&id, NULL, t_fun, (void*) iarg); } diff --git a/tests/incremental/13-restart-write/04-malloc-node.json b/tests/incremental/13-restart-write/04-malloc-node.json index f65fca9568..b68cac8440 100644 --- a/tests/incremental/13-restart-write/04-malloc-node.json +++ b/tests/incremental/13-restart-write/04-malloc-node.json @@ -4,6 +4,10 @@ "sided": { "enabled": false } + }, + "postsolver": { + "enabled": true, + "superstable-reached": false } }, "ana": { diff --git a/tests/incremental/13-restart-write/04-malloc-node.patch b/tests/incremental/13-restart-write/04-malloc-node.patch index e8eedc4bb0..3fc4d75e19 100644 --- a/tests/incremental/13-restart-write/04-malloc-node.patch +++ b/tests/incremental/13-restart-write/04-malloc-node.patch @@ -1,13 +1,19 @@ -diff --git tests/incremental/13-restart-write/04-malloc-node.c tests/incremental/13-restart-write/04-malloc-node.c -index 87bbc0f14..3cd6dc5c7 100644 --- tests/incremental/13-restart-write/04-malloc-node.c +++ tests/incremental/13-restart-write/04-malloc-node.c -@@ -11,6 +11,8 @@ int main() { +@@ -3,6 +3,7 @@ + + void *t_fun(void *arg) { + int *iarg = (int*) arg; ++ int y = 0; // NORACE (old access) + *iarg = 1; // RACE (without mallocFresh) + return NULL; + } +@@ -11,6 +12,8 @@ int main() { pthread_t id; int *iarg; - + + assert(1); -+ ++ int x = 0; // NORACE (old access) for (int i = 0; i < 10; i++) { iarg = malloc(sizeof(int)); - *iarg = 0; + *iarg = 0; // RACE (without mallocFresh) From 121fcc178eea7b69b9c0a1aa5818cb714b37644b Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 20 Apr 2022 16:05:41 +0300 Subject: [PATCH 329/402] Add test for if condition race location --- .../regression/04-mutex/81-if-cond-race-loc.c | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 tests/regression/04-mutex/81-if-cond-race-loc.c diff --git a/tests/regression/04-mutex/81-if-cond-race-loc.c b/tests/regression/04-mutex/81-if-cond-race-loc.c new file mode 100644 index 0000000000..b5228f6e70 --- /dev/null +++ b/tests/regression/04-mutex/81-if-cond-race-loc.c @@ -0,0 +1,26 @@ +#include +#include + +int myglobal; + +void *t_fun(void *arg) { + // awkward formatting to check that warning is just on condition expression, not entire if + if // NORACE + (myglobal > 0) { // RACE! + printf("Stupid!"); + printf("Stupid!"); + printf("Stupid!"); + printf("Stupid!"); + printf("Stupid!"); + printf("Stupid!"); + } + return NULL; +} + +int main(void) { + pthread_t id; + pthread_create(&id, NULL, t_fun, NULL); + myglobal=myglobal+1; // RACE! + pthread_join (id, NULL); + return 0; +} From 9c60ef14c4e26f5d014766df5bdfddc732853a08 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Tue, 3 May 2022 12:11:44 +0300 Subject: [PATCH 330/402] Change Cilfacade.get_stmtLoc to expression locations (where possible) (closes #689) Ideally we would have a choice and update edge locations instead of nodes, but they cannot be referenced. --- .semgrep/cil.yml | 1 + src/util/cilfacade0.ml | 28 ++++++++++++++++++++++++---- 2 files changed, 25 insertions(+), 4 deletions(-) diff --git a/.semgrep/cil.yml b/.semgrep/cil.yml index 7cc2e78f40..5c12ae5a71 100644 --- a/.semgrep/cil.yml +++ b/.semgrep/cil.yml @@ -6,6 +6,7 @@ rules: - pattern: Cil.typeOfInit - pattern: Cil.typeOffset - pattern: Cil.get_stmtLoc + - pattern: Cil.get_instrLoc paths: exclude: - cilfacade0.ml diff --git a/src/util/cilfacade0.ml b/src/util/cilfacade0.ml index dfe6dd031b..4d3e56f48a 100644 --- a/src/util/cilfacade0.ml +++ b/src/util/cilfacade0.ml @@ -16,12 +16,32 @@ let rec get_labelsLoc = function else loc -let get_stmtkindLoc = Cil.get_stmtLoc (* CIL has a confusing name for this function *) +(** Following functions are similar to [Cil] versions, but return expression location instead of entire statement location, where possible. *) +(* Ideally we would have both copies of the functions available, but UpdateCil would have to be adapted per-stmtkind/instr to store and update either one or two locations. *) -let get_stmtLoc stmt = +(** Get expression location for [Cil.instr]. *) +let get_instrLoc = function + | Set (_, _, _loc, eloc) -> eloc + | Call (_, _, _, _loc, eloc) -> eloc + | Asm (_, _, _, _, _, loc) -> loc + | VarDecl (_, loc) -> loc + +(** Get expression location for [Cil.stmt]. *) +(* confusingly CIL.get_stmtLoc works on stmtkind instead *) +let rec get_stmtLoc stmt = match stmt.skind with - (* Cil.get_stmtLoc returns Cil.locUnknown in these cases, so try labels instead *) + (* no stmtkind/instr location in these cases, so try labels instead *) | Instr [] | Block {bstmts = []; _} -> get_labelsLoc stmt.labels - | _ -> get_stmtkindLoc stmt.skind + + | Instr (hd :: _) -> get_instrLoc hd + | Return (_, loc) -> loc + | Goto (_, loc) -> loc + | ComputedGoto (_, loc) -> loc + | Break loc -> loc + | Continue loc -> loc + | If (_, _, _, _loc, eloc) -> eloc + | Switch (_, _, _, _loc, eloc) -> eloc + | Loop (_, _loc, eloc, _, _) -> eloc + | Block {bstmts = hd :: _; _} -> get_stmtLoc hd From 6bfc853f186ac9d2fbd08902ab1e8b7487e705f3 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Tue, 3 May 2022 12:12:09 +0300 Subject: [PATCH 331/402] Add EvalAssert TODO-s about not using Cilfacade for locations --- src/transform/evalAssert.ml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/transform/evalAssert.ml b/src/transform/evalAssert.ml index f2e5a66ce2..51c7df6380 100644 --- a/src/transform/evalAssert.ml +++ b/src/transform/evalAssert.ml @@ -106,16 +106,16 @@ module EvalAssert = struct let rec instrument_instructions = function | i1 :: ((i2 :: _) as is) -> (* List contains successor statement, use location of successor for values *) - let loc = get_instrLoc i2 in + let loc = get_instrLoc i2 in (* TODO: why not using Cilfacade.get_instrLoc? *) i1 :: ((instrument i1 loc) @ instrument_instructions is) | [i] when unique_succ -> (* Last statement in list *) (* Successor of it has only one predecessor, we can query for the value there *) - let loc = get_stmtLoc (List.hd s.succs).skind in + let loc = get_stmtLoc (List.hd s.succs).skind in (* TODO: why not using Cilfacade.get_stmtLoc? *) i :: (instrument i loc) | [i] when s.succs <> [] -> (* Successor has multiple predecessors, results may be imprecise but remain correct *) - let loc = get_stmtLoc (List.hd s.succs).skind in + let loc = get_stmtLoc (List.hd s.succs).skind in (* TODO: why not using Cilfacade.get_stmtLoc? *) i :: (instrument i loc) | x -> x in @@ -134,7 +134,7 @@ module EvalAssert = struct match s.preds with | [p1; p2] when not only_at_locks -> (* exactly two predecessors -> join point, assert locals if they changed *) - let join_loc = get_stmtLoc s.skind in + let join_loc = get_stmtLoc s.skind in (* TODO: why not using Cilfacade.get_stmtLoc? *) (* Possible enhancement: It would be nice to only assert locals here that were modified in either branch if trans.assert.full is false *) let asserts = make_assert join_loc None in self#queueInstr asserts; () @@ -153,7 +153,7 @@ module EvalAssert = struct let add_asserts block = if block.bstmts <> [] then let with_asserts = - let b_loc = get_stmtLoc (List.hd block.bstmts).skind in + let b_loc = get_stmtLoc (List.hd block.bstmts).skind in (* TODO: why not using Cilfacade.get_stmtLoc? *) let b_assert_instr = asserts b_loc vars in [cStmt "{ %I:asserts %S:b }" (fun n t -> makeVarinfo true "unknown" (TVoid [])) b_loc [("asserts", FI b_assert_instr); ("b", FS block.bstmts)]] in From 71c7e1cbbd1551e5150b8814594514174ef1991a Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Tue, 3 May 2022 17:54:31 +0300 Subject: [PATCH 332/402] Disable free races and args invalidation in zstd-race conf --- conf/zstd-race.json | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/conf/zstd-race.json b/conf/zstd-race.json index 64ff2ea07a..e18e8d9077 100644 --- a/conf/zstd-race.json +++ b/conf/zstd-race.json @@ -23,13 +23,17 @@ "ZSTD_customMalloc", "ZSTD_customCalloc" ] + }, + "race": { + "free": false } }, "sem": { "unknown_function": { "spawn": false, "invalidate": { - "globals": false + "globals": false, + "args": false } } }, From 75798a555987475b200ccf4e4041ff98a87deb6a Mon Sep 17 00:00:00 2001 From: Michael Schwarz Date: Wed, 4 May 2022 10:51:29 +0200 Subject: [PATCH 333/402] Option to only destabilize access globals --- src/solvers/td3.ml | 16 +++++++++++-- src/util/options.schema.json | 12 ++++++++++ .../13-restart-write/09-mutex-simple-access.c | 23 ++++++++++++++++++ .../09-mutex-simple-access.json | 11 +++++++++ .../09-mutex-simple-access.patch | 24 +++++++++++++++++++ 5 files changed, 84 insertions(+), 2 deletions(-) create mode 100644 tests/incremental/13-restart-write/09-mutex-simple-access.c create mode 100644 tests/incremental/13-restart-write/09-mutex-simple-access.json create mode 100644 tests/incremental/13-restart-write/09-mutex-simple-access.patch diff --git a/src/solvers/td3.ml b/src/solvers/td3.ml index 268ff10cdb..18c36dd21d 100644 --- a/src/solvers/td3.ml +++ b/src/solvers/td3.ml @@ -131,6 +131,8 @@ module WP = (* If true, incremental side-effected var restart will only restart destabilized globals (using hack). If false, it will restart all destabilized side-effected vars. *) let restart_only_globals = GobConfig.get_bool "incremental.restart.sided.only-global" in + let restart_only_access = GobConfig.get_bool "incremental.restart.sided.only-access" in + let restart_destab_with_sides = GobConfig.get_bool "incremental.restart.sided.destab-with-sides" in (* If true, wpoint will be restarted to bot when added. This allows incremental to avoid reusing and republishing imprecise local values due to globals (which get restarted). *) @@ -580,7 +582,14 @@ module WP = let w = HM.find_default side_dep x VS.empty in HM.remove side_dep x; - if not (VS.is_empty w) && (not restart_only_globals || Node.equal (S.Var.node x) (Function Cil.dummyFunDec)) && not (S.Var.is_write_only x) then ( + let should_restart = + if restart_only_access then + S.Var.is_write_only x + else + (not restart_only_globals || Node.equal (S.Var.node x) (Function Cil.dummyFunDec)) && (not (S.Var.is_write_only x)) + in + + if not (VS.is_empty w) && should_restart then ( (* restart side-effected var *) restart_leaf x; @@ -593,7 +602,10 @@ module WP = if tracing then trace "sol2" "stable remove %a\n" S.Var.pretty_trace y; HM.remove stable y; HM.remove superstable y; - destabilize_with_side ~front:false y + if restart_destab_with_sides then + destabilize_with_side ~front:false y + else + destabilize_normal ~front:false y ) w ); diff --git a/src/util/options.schema.json b/src/util/options.schema.json index 260f3ca988..987d8f32a3 100644 --- a/src/util/options.schema.json +++ b/src/util/options.schema.json @@ -1050,6 +1050,18 @@ "description": "TODO", "type": "boolean", "default": false + }, + "only-access" : { + "title" : "incremental.restart.sided.only-access", + "description" : "TODO", + "type" : "boolean", + "default" : false + }, + "destab-with-sides": { + "title" : "incremental.restart.sided.destab-with-sides", + "description" : "TODO", + "type" : "boolean", + "default" : true } }, "additionalProperties": false diff --git a/tests/incremental/13-restart-write/09-mutex-simple-access.c b/tests/incremental/13-restart-write/09-mutex-simple-access.c new file mode 100644 index 0000000000..82c1642a93 --- /dev/null +++ b/tests/incremental/13-restart-write/09-mutex-simple-access.c @@ -0,0 +1,23 @@ +#include +#include + +int myglobal; +pthread_mutex_t mutex1 = PTHREAD_MUTEX_INITIALIZER; +pthread_mutex_t mutex2 = PTHREAD_MUTEX_INITIALIZER; + +void *t_fun(void *arg) { + pthread_mutex_lock(&mutex1); + myglobal=myglobal+1; // RACE! + pthread_mutex_unlock(&mutex1); + return NULL; +} + +int main(void) { + pthread_t id; + pthread_create(&id, NULL, t_fun, NULL); + pthread_mutex_lock(&mutex2); + myglobal=myglobal+1; // RACE! + pthread_mutex_unlock(&mutex2); + pthread_join (id, NULL); + return 0; +} diff --git a/tests/incremental/13-restart-write/09-mutex-simple-access.json b/tests/incremental/13-restart-write/09-mutex-simple-access.json new file mode 100644 index 0000000000..d1a0187785 --- /dev/null +++ b/tests/incremental/13-restart-write/09-mutex-simple-access.json @@ -0,0 +1,11 @@ +{ + "incremental": { + "restart": { + "sided": { + "enabled": true, + "only-access": true, + "destab-with-sides": false + } + } + } +} diff --git a/tests/incremental/13-restart-write/09-mutex-simple-access.patch b/tests/incremental/13-restart-write/09-mutex-simple-access.patch new file mode 100644 index 0000000000..31867f7b2e --- /dev/null +++ b/tests/incremental/13-restart-write/09-mutex-simple-access.patch @@ -0,0 +1,24 @@ +--- tests/incremental/13-restart-write/09-mutex-simple-access.c ++++ tests/incremental/13-restart-write/09-mutex-simple-access.c +@@ -7,7 +7,7 @@ pthread_mutex_t mutex2 = PTHREAD_MUTEX_INITIALIZER; + + void *t_fun(void *arg) { + pthread_mutex_lock(&mutex1); +- myglobal=myglobal+1; // RACE! ++ myglobal=myglobal+1; // NORACE + pthread_mutex_unlock(&mutex1); + return NULL; + } +@@ -15,9 +15,9 @@ void *t_fun(void *arg) { + int main(void) { + pthread_t id; + pthread_create(&id, NULL, t_fun, NULL); +- pthread_mutex_lock(&mutex2); +- myglobal=myglobal+1; // RACE! +- pthread_mutex_unlock(&mutex2); ++ pthread_mutex_lock(&mutex1); ++ myglobal=myglobal+1; // NORACE ++ pthread_mutex_unlock(&mutex1); + pthread_join (id, NULL); + return 0; + } From 05cb11b647825b205142651f1c0ef64dbe7f62a0 Mon Sep 17 00:00:00 2001 From: Michael Schwarz Date: Wed, 4 May 2022 13:06:16 +0200 Subject: [PATCH 334/402] mv tests --- .../12-mutex-simple-access.c} | 0 .../12-mutex-simple-access.json} | 0 .../12-mutex-simple-access.patch} | 0 3 files changed, 0 insertions(+), 0 deletions(-) rename tests/incremental/{13-restart-write/09-mutex-simple-access.c => 11-restart/12-mutex-simple-access.c} (100%) rename tests/incremental/{13-restart-write/09-mutex-simple-access.json => 11-restart/12-mutex-simple-access.json} (100%) rename tests/incremental/{13-restart-write/09-mutex-simple-access.patch => 11-restart/12-mutex-simple-access.patch} (100%) diff --git a/tests/incremental/13-restart-write/09-mutex-simple-access.c b/tests/incremental/11-restart/12-mutex-simple-access.c similarity index 100% rename from tests/incremental/13-restart-write/09-mutex-simple-access.c rename to tests/incremental/11-restart/12-mutex-simple-access.c diff --git a/tests/incremental/13-restart-write/09-mutex-simple-access.json b/tests/incremental/11-restart/12-mutex-simple-access.json similarity index 100% rename from tests/incremental/13-restart-write/09-mutex-simple-access.json rename to tests/incremental/11-restart/12-mutex-simple-access.json diff --git a/tests/incremental/13-restart-write/09-mutex-simple-access.patch b/tests/incremental/11-restart/12-mutex-simple-access.patch similarity index 100% rename from tests/incremental/13-restart-write/09-mutex-simple-access.patch rename to tests/incremental/11-restart/12-mutex-simple-access.patch From 19a522949e22613fa0ed543a858963df12780e37 Mon Sep 17 00:00:00 2001 From: Michael Schwarz Date: Wed, 4 May 2022 13:09:59 +0200 Subject: [PATCH 335/402] fix patch --- tests/incremental/11-restart/12-mutex-simple-access.patch | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/incremental/11-restart/12-mutex-simple-access.patch b/tests/incremental/11-restart/12-mutex-simple-access.patch index 31867f7b2e..8be2c16b66 100644 --- a/tests/incremental/11-restart/12-mutex-simple-access.patch +++ b/tests/incremental/11-restart/12-mutex-simple-access.patch @@ -1,5 +1,5 @@ ---- tests/incremental/13-restart-write/09-mutex-simple-access.c -+++ tests/incremental/13-restart-write/09-mutex-simple-access.c +--- tests/incremental/11-restart/12-mutex-simple-access.c ++++ tests/incremental/11-restart/12-mutex-simple-access.c @@ -7,7 +7,7 @@ pthread_mutex_t mutex2 = PTHREAD_MUTEX_INITIALIZER; void *t_fun(void *arg) { From 5cec6c219e36a4ff445b79a649fb0758ae726190 Mon Sep 17 00:00:00 2001 From: Michael Schwarz Date: Wed, 4 May 2022 15:48:47 +0200 Subject: [PATCH 336/402] Add comment on origin to test --- tests/incremental/11-restart/12-mutex-simple-access.c | 1 + tests/incremental/11-restart/12-mutex-simple-access.patch | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/incremental/11-restart/12-mutex-simple-access.c b/tests/incremental/11-restart/12-mutex-simple-access.c index 82c1642a93..8a1c25768b 100644 --- a/tests/incremental/11-restart/12-mutex-simple-access.c +++ b/tests/incremental/11-restart/12-mutex-simple-access.c @@ -1,3 +1,4 @@ +// Same as 13-restart-write/01-mutex-simple #include #include diff --git a/tests/incremental/11-restart/12-mutex-simple-access.patch b/tests/incremental/11-restart/12-mutex-simple-access.patch index 8be2c16b66..655af16f1b 100644 --- a/tests/incremental/11-restart/12-mutex-simple-access.patch +++ b/tests/incremental/11-restart/12-mutex-simple-access.patch @@ -1,6 +1,6 @@ --- tests/incremental/11-restart/12-mutex-simple-access.c +++ tests/incremental/11-restart/12-mutex-simple-access.c -@@ -7,7 +7,7 @@ pthread_mutex_t mutex2 = PTHREAD_MUTEX_INITIALIZER; +@@ -8,7 +8,7 @@ pthread_mutex_t mutex2 = PTHREAD_MUTEX_INITIALIZER; void *t_fun(void *arg) { pthread_mutex_lock(&mutex1); @@ -9,7 +9,7 @@ pthread_mutex_unlock(&mutex1); return NULL; } -@@ -15,9 +15,9 @@ void *t_fun(void *arg) { +@@ -16,9 +16,9 @@ void *t_fun(void *arg) { int main(void) { pthread_t id; pthread_create(&id, NULL, t_fun, NULL); From 0709d82d1ad90a0882e22fd93e3cee8756061248 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 5 May 2022 09:49:33 +0300 Subject: [PATCH 337/402] Add symb_locks test with irrelevant index access --- tests/regression/06-symbeq/37-funloop_index.c | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 tests/regression/06-symbeq/37-funloop_index.c diff --git a/tests/regression/06-symbeq/37-funloop_index.c b/tests/regression/06-symbeq/37-funloop_index.c new file mode 100644 index 0000000000..831ad62769 --- /dev/null +++ b/tests/regression/06-symbeq/37-funloop_index.c @@ -0,0 +1,36 @@ +// PARAM: --disable ana.mutex.disjoint_types --set ana.activated[+] "'var_eq'" --set ana.activated[+] "'symb_locks'" +// copy of 06/02 with additional index accesses +#include +#include + +struct cache_entry { + int refs; + pthread_mutex_t refs_mutex; +} cache[10]; + +void cache_entry_addref(struct cache_entry *entry) { + pthread_mutex_lock(&entry->refs_mutex); + entry->refs++; // NORACE + (*entry).refs++; // NORACE + entry[0].refs++; // NORACE + pthread_mutex_unlock(&entry->refs_mutex); +} + +void *t_fun(void *arg) { + int i; + for(i=0; i<10; i++) + cache_entry_addref(&cache[i]); // NORACE + return NULL; +} + +int main () { + for (int i = 0; i < 10; i++) + pthread_mutex_init(&cache[i].refs_mutex, NULL); + + int i; + pthread_t t1; + pthread_create(&t1, NULL, t_fun, NULL); + for(i=0; i<10; i++) + cache_entry_addref(&cache[i]); // NORACE + return 0; +} From 30c1d7aedabe4deb1f60aba45c1d07f8f8b66f1a Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 5 May 2022 10:00:23 +0300 Subject: [PATCH 338/402] Add var_eq EqualSet tracing --- src/analyses/varEq.ml | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/analyses/varEq.ml b/src/analyses/varEq.ml index ce93e043dd..29ff7b2453 100644 --- a/src/analyses/varEq.ml +++ b/src/analyses/varEq.ml @@ -519,7 +519,8 @@ struct D.B.fold add es (Queries.ES.empty ()) let rec eq_set_clos e s = - match e with + if M.tracing then M.traceli "var_eq" "eq_set_clos %a\n" d_plainexp e; + let r = match e with | SizeOf _ | SizeOfE _ | SizeOfStr _ @@ -541,6 +542,9 @@ struct Queries.ES.map (fun e -> CastE (t,e)) (eq_set_clos e s) | Question _ -> failwith "Logical operations should be compiled away by CIL." | _ -> failwith "Unmatched pattern." + in + if M.tracing then M.traceu "var_eq" "eq_set_clos %a = %a\n" d_plainexp e Queries.ES.pretty r; + r let query ctx (type a) (x: a Queries.t): a Queries.result = @@ -550,6 +554,7 @@ struct | Queries.EqualSet e -> let r = eq_set_clos e ctx.local in (* Messages.warn ~msg:("equset of "^(sprint 80 (d_exp () e))^" is "^(Queries.ES.short 80 r)) (); *) + if M.tracing then M.tracel "var_eq" "equalset %a = %a\n" d_plainexp e Queries.ES.pretty r; r | _ -> Queries.Result.top x From 11cc869352318dcc044bcf1a19b2b55e7d8dfb07 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 5 May 2022 10:01:15 +0300 Subject: [PATCH 339/402] Quick fix var_eq eq_set_clos for IndexPI --- src/analyses/varEq.ml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/analyses/varEq.ml b/src/analyses/varEq.ml index 29ff7b2453..93c01addba 100644 --- a/src/analyses/varEq.ml +++ b/src/analyses/varEq.ml @@ -521,6 +521,8 @@ struct let rec eq_set_clos e s = if M.tracing then M.traceli "var_eq" "eq_set_clos %a\n" d_plainexp e; let r = match e with + | BinOp ((PlusPI | IndexPI), e1, e2, _) -> + eq_set_clos e1 s (* TODO: what about e2? add to some Index offset to all? *) | SizeOf _ | SizeOfE _ | SizeOfStr _ From dd432000a7f062ee8c93e1352f81fe0c1e109110 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 5 May 2022 12:04:12 +0300 Subject: [PATCH 340/402] Add chrony Name2IPAddress extracted test for symb_locks --- .../06-symbeq/38-chrony-name2ipaddress.c | 219 ++++++++++++++++++ 1 file changed, 219 insertions(+) create mode 100644 tests/regression/06-symbeq/38-chrony-name2ipaddress.c diff --git a/tests/regression/06-symbeq/38-chrony-name2ipaddress.c b/tests/regression/06-symbeq/38-chrony-name2ipaddress.c new file mode 100644 index 0000000000..6a4fec5ac9 --- /dev/null +++ b/tests/regression/06-symbeq/38-chrony-name2ipaddress.c @@ -0,0 +1,219 @@ +// PARAM: --set ana.activated[+] "'var_eq'" --set ana.activated[+] "'symb_locks'" --set ana.activated[+] "'mallocFresh'" --set ana.malloc.wrappers '["Malloc"]' --disable sem.unknown_function.spawn --disable sem.unknown_function.invalidate.globals +#include +#include +// #include +// #include +#include +#include + +void * +Malloc(size_t size) +{ + void *r; + + r = malloc(size); + // if (!r && size) + // LOG_FATAL("Could not allocate memory"); + + return r; +} + +typedef enum { + DNS_Success, + DNS_TryAgain, + DNS_Failure +} DNS_Status; + +typedef struct { + union { + uint32_t in4; + uint8_t in6[16]; + uint32_t id; + } addr; + uint16_t family; + uint16_t _pad; +} IPAddr; + +#define DNS_MAX_ADDRESSES 16 +#define IPADDR_UNSPEC 0 +#define IPADDR_INET4 1 +#define IPADDR_INET6 2 +#define IPADDR_ID 3 + +static int address_family = IPADDR_UNSPEC; + +int +UTI_StringToIP(const char *addr, IPAddr *ip) +{ + struct in_addr in4; +#ifdef FEAT_IPV6 + struct in6_addr in6; +#endif + + if (inet_pton(AF_INET, addr, &in4) > 0) { + ip->family = IPADDR_INET4; + ip->_pad = 0; + ip->addr.in4 = ntohl(in4.s_addr); + return 1; + } + +#ifdef FEAT_IPV6 + if (inet_pton(AF_INET6, addr, &in6) > 0) { + ip->family = IPADDR_INET6; + ip->_pad = 0; + memcpy(ip->addr.in6, in6.s6_addr, sizeof (ip->addr.in6)); + return 1; + } +#endif + + return 0; +} + + +#define MIN(x, y) ((x) < (y) ? (x) : (y)) + +DNS_Status +DNS_Name2IPAddress(const char *name, IPAddr *ip_addrs, int max_addrs) +{ + struct addrinfo hints, *res, *ai; + int i, result; + IPAddr ip; + + max_addrs = MIN(max_addrs, DNS_MAX_ADDRESSES); + + for (i = 0; i < max_addrs; i++) + ip_addrs[i].family = IPADDR_UNSPEC; + +// #if 0 + /* Avoid calling getaddrinfo() if the name is an IP address */ + if (UTI_StringToIP(name, &ip)) { + if (address_family != IPADDR_UNSPEC && ip.family != address_family) + return DNS_Failure; + if (max_addrs >= 1) + ip_addrs[0] = ip; + return DNS_Success; + } + + memset(&hints, 0, sizeof (hints)); + + switch (address_family) { + case IPADDR_INET4: + hints.ai_family = AF_INET; + break; +#ifdef FEAT_IPV6 + case IPADDR_INET6: + hints.ai_family = AF_INET6; + break; +#endif + default: + hints.ai_family = AF_UNSPEC; + } + hints.ai_socktype = SOCK_DGRAM; + + result = getaddrinfo(name, NULL, &hints, &res); + + if (result) { +#ifdef FORCE_DNSRETRY + return DNS_TryAgain; +#else + return result == EAI_AGAIN ? DNS_TryAgain : DNS_Failure; +#endif + } + + for (ai = res, i = 0; i < max_addrs && ai != NULL; ai = ai->ai_next) { + switch (ai->ai_family) { + case AF_INET: + if (address_family != IPADDR_UNSPEC && address_family != IPADDR_INET4) + continue; + ip_addrs[i].family = IPADDR_INET4; + ip_addrs[i].addr.in4 = ntohl(((struct sockaddr_in *)ai->ai_addr)->sin_addr.s_addr); + i++; + break; +#ifdef FEAT_IPV6 + case AF_INET6: + if (address_family != IPADDR_UNSPEC && address_family != IPADDR_INET6) + continue; + /* Don't return an address that would lose a scope ID */ + if (((struct sockaddr_in6 *)ai->ai_addr)->sin6_scope_id != 0) + continue; + ip_addrs[i].family = IPADDR_INET6; + memcpy(&ip_addrs[i].addr.in6, &((struct sockaddr_in6 *)ai->ai_addr)->sin6_addr.s6_addr, + sizeof (ip_addrs->addr.in6)); + i++; + break; +#endif + } + } + + freeaddrinfo(res); +// #endif + + return !max_addrs || ip_addrs[0].family != IPADDR_UNSPEC ? DNS_Success : DNS_Failure; +} + +struct DNS_Async_Instance { + const char *name; + DNS_Status status; + IPAddr addresses[DNS_MAX_ADDRESSES]; + // DNS_NameResolveHandler handler; + // void *arg; + pthread_mutex_t mutex; + + pthread_t thread; + // int pipe[2]; +}; + +static pthread_mutex_t privops_lock = PTHREAD_MUTEX_INITIALIZER; + +/* ================================================== */ + +static void * +start_resolving(void *anything) +{ + struct DNS_Async_Instance *inst = (struct DNS_Async_Instance *)anything; + + pthread_mutex_lock(&inst->mutex); + inst->status = DNS_Name2IPAddress(inst->name, inst->addresses, DNS_MAX_ADDRESSES); + pthread_mutex_unlock(&inst->mutex); + + /* Notify the main thread that the result is ready */ + // if (write(inst->pipe[1], "", 1) < 0) + // ; + + return NULL; +} + + +#define MallocNew(T) ((T *) Malloc(sizeof(T))) + +void +DNS_Name2IPAddressAsync(const char *name) +{ + struct DNS_Async_Instance *inst; + + inst = MallocNew(struct DNS_Async_Instance); + inst->name = name; + // inst->handler = handler; + // inst->arg = anything; + inst->status = DNS_Failure; + pthread_mutex_init(&inst->mutex, NULL); + + // if (pipe(inst->pipe)) { + // LOG_FATAL("pipe() failed"); + // } + + // UTI_FdSetCloexec(inst->pipe[0]); + // UTI_FdSetCloexec(inst->pipe[1]); + + if (pthread_create(&inst->thread, NULL, start_resolving, inst)) { + // LOG_FATAL("pthread_create() failed"); + } + + // SCH_AddFileHandler(inst->pipe[0], SCH_FILE_INPUT, end_resolving, inst); +} + +int main() { + DNS_Name2IPAddressAsync("foo"); + DNS_Name2IPAddressAsync("bar"); + return 0; +} From 1ba9590b2f0678255f644acfa368cd15dcf0c990 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 5 May 2022 12:05:55 +0300 Subject: [PATCH 341/402] Add symb_locks tracing --- src/analyses/symbLocks.ml | 7 ++++++- src/cdomains/exp.ml | 3 +++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/analyses/symbLocks.ml b/src/analyses/symbLocks.ml index ccf0ffe9d7..a8c74aa3c8 100644 --- a/src/analyses/symbLocks.ml +++ b/src/analyses/symbLocks.ml @@ -59,8 +59,12 @@ struct | a when not (Queries.ES.is_bot a) -> Queries.ES.add e a | _ -> Queries.ES.singleton e in + if M.tracing then M.tracel "symb_locks" "get_all_locks exps %a = %a\n" d_plainexp e Queries.ES.pretty exps; + if M.tracing then M.tracel "symb_locks" "get_all_locks st = %a\n" D.pretty st; let add_locks x xs = PS.union (get_locks x st) xs in - Queries.ES.fold add_locks exps (PS.empty ()) + let r = Queries.ES.fold add_locks exps (PS.empty ()) in + if M.tracing then M.tracel "symb_locks" "get_all_locks %a = %a\n" d_plainexp e PS.pretty r; + r let same_unknown_index (ask: Queries.ask) exp slocks = let uk_index_equal i1 i2 = ask.f (Queries.MustBeEqual (i1, i2)) in @@ -148,6 +152,7 @@ struct *) let one_perelem (e,a,l) xs = (* ignore (printf "one_perelem (%a,%a,%a)\n" Exp.pretty e Exp.pretty a Exp.pretty l); *) + if M.tracing then M.tracel "symb_locks" "one_perelem (%a,%a,%a)\n" Exp.pretty e Exp.pretty a Exp.pretty l; match Exp.fold_offs (Exp.replace_base (dummyFunDec.svar,`NoOffset) e l) with | Some (v, o) -> (* ignore (printf "adding lock %s\n" l); *) diff --git a/src/cdomains/exp.ml b/src/cdomains/exp.ml index 35c585f8ef..9fd075c204 100644 --- a/src/cdomains/exp.ml +++ b/src/cdomains/exp.ml @@ -1,6 +1,8 @@ open Pretty open Cil +module M = Messages + module Exp = struct include CilType.Exp @@ -331,6 +333,7 @@ struct List.rev el, fs let from_exps a l : t option = + if M.tracing then M.tracel "symb_locks" "from_exps %a (%s) %a (%s)\n" d_plainexp a (ees_to_str (toEl a)) d_plainexp l (ees_to_str (toEl l)); let a, l = toEl a, toEl l in (* ignore (printf "from_exps:\n %s\n %s\n" (ees_to_str a) (ees_to_str l)); *) (*let rec fold_left2 f a xs ys = From f5c4e895b2ed3cfa0c0e74347de1fdf7bc71c56f Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 5 May 2022 12:06:33 +0300 Subject: [PATCH 342/402] Quick fix symb_locks toEl for IndexPI --- src/cdomains/exp.ml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/cdomains/exp.ml b/src/cdomains/exp.ml index 9fd075c204..9d2b7fee07 100644 --- a/src/cdomains/exp.ml +++ b/src/cdomains/exp.ml @@ -292,6 +292,8 @@ struct in let rec helper exp = match exp with + | BinOp ((PlusPI | IndexPI), e1, e2, _) -> + helper e1 (* TODO: what about e2? add to some Index offset to all? *) | SizeOf _ | SizeOfE _ | SizeOfStr _ From 752d16caf2beae97f7ecbb08bdb071de435b731c Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 5 May 2022 12:08:18 +0300 Subject: [PATCH 343/402] Fix symb_locks toEl for StartOf --- src/cdomains/exp.ml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/cdomains/exp.ml b/src/cdomains/exp.ml index 9d2b7fee07..b4d1890496 100644 --- a/src/cdomains/exp.ml +++ b/src/cdomains/exp.ml @@ -301,12 +301,13 @@ struct | AlignOfE _ | UnOp _ | BinOp _ - | StartOf _ | Const _ -> raise NotSimpleEnough | Lval (Var v, os) -> EVar v :: conv_o os | Lval (Mem e, os) -> helper e @ [EDeref] @ conv_o os | AddrOf (Var v, os) -> EVar v :: conv_o os @ [EAddr] | AddrOf (Mem e, os) -> helper e @ [EDeref] @ conv_o os @ [EAddr] + | StartOf (Var v, os) -> EVar v :: conv_o os @ [EAddr] + | StartOf (Mem e, os) -> helper e @ [EDeref] @ conv_o os @ [EAddr] | CastE (_,e) -> helper e | Question _ -> failwith "Logical operations should be compiled away by CIL." | _ -> failwith "Unmatched pattern." From 180ed23bcf5c64bd02b7e02e26c43817313bd542 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 5 May 2022 12:09:04 +0300 Subject: [PATCH 344/402] Fix VarEq.may_change with constant Previously "changing" a constant could change anything. --- src/analyses/varEq.ml | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/analyses/varEq.ml b/src/analyses/varEq.ml index 93c01addba..7bc952e598 100644 --- a/src/analyses/varEq.ml +++ b/src/analyses/varEq.ml @@ -315,7 +315,8 @@ struct | _ -> failwith "Unmatched pattern." in let r = - if Queries.LS.is_top bls || Queries.LS.mem (dummyFunDec.svar, `NoOffset) bls + if Cil.isConstant b then false + else if Queries.LS.is_top bls || Queries.LS.mem (dummyFunDec.svar, `NoOffset) bls then ((*Messages.warn "No PT-set: switching to types ";*) type_may_change_apt a ) else Queries.LS.exists (lval_may_change_pt a) bls in @@ -323,7 +324,9 @@ struct then (Messages.warn ~msg:("Kill " ^sprint 80 (Exp.pretty () a)^" because of "^sprint 80 (Exp.pretty () b)) (); r) else (Messages.warn ~msg:("Keep " ^sprint 80 (Exp.pretty () a)^" because of "^sprint 80 (Exp.pretty () b)) (); r) Messages.warn ~msg:(sprint 80 (Exp.pretty () b) ^" changed lvalues: "^sprint 80 (Queries.LS.pretty () bls)) (); - *) r + *) + if M.tracing then M.tracel "var_eq" "may_change %a %a = %B\n" CilType.Exp.pretty b CilType.Exp.pretty a r; + r (* Remove elements, that would change if the given lval would change.*) let remove_exp ask (e:exp) (st:D.t) : D.t = From 653d0bb5786383ef00433397eff9edebf97c02c8 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 5 May 2022 12:41:10 +0300 Subject: [PATCH 345/402] Enable all code paths in chrony-name2ipaddress This makes it match default chrony analysis. --- tests/regression/06-symbeq/38-chrony-name2ipaddress.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tests/regression/06-symbeq/38-chrony-name2ipaddress.c b/tests/regression/06-symbeq/38-chrony-name2ipaddress.c index 6a4fec5ac9..05259683ee 100644 --- a/tests/regression/06-symbeq/38-chrony-name2ipaddress.c +++ b/tests/regression/06-symbeq/38-chrony-name2ipaddress.c @@ -1,10 +1,11 @@ -// PARAM: --set ana.activated[+] "'var_eq'" --set ana.activated[+] "'symb_locks'" --set ana.activated[+] "'mallocFresh'" --set ana.malloc.wrappers '["Malloc"]' --disable sem.unknown_function.spawn --disable sem.unknown_function.invalidate.globals +// PARAM: --set ana.activated[+] "'var_eq'" --set ana.activated[+] "'symb_locks'" --set ana.activated[+] "'mallocFresh'" --set ana.malloc.wrappers '["Malloc"]' --disable sem.unknown_function.spawn --disable sem.unknown_function.invalidate.globals --set pre.cppflags[+] -D_FORTIFY_SOURCE=2 --set pre.cppflags[+] -O3 #include #include // #include // #include #include #include +#include void * Malloc(size_t size) @@ -40,6 +41,8 @@ typedef struct { #define IPADDR_INET6 2 #define IPADDR_ID 3 +#define FEAT_IPV6 1 + static int address_family = IPADDR_UNSPEC; int From a4be26255157b495fc74b6353d83c856a3ebd5a7 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 5 May 2022 12:41:33 +0300 Subject: [PATCH 346/402] Add var_eq add_eq tracing --- src/analyses/varEq.ml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/analyses/varEq.ml b/src/analyses/varEq.ml index 7bc952e598..9ff73d090e 100644 --- a/src/analyses/varEq.ml +++ b/src/analyses/varEq.ml @@ -379,6 +379,12 @@ struct let st = *) let lvt = unrollType @@ Cilfacade.typeOfLval lv in (* Messages.warn ~msg:(sprint 80 (d_type () lvt)) (); *) + if M.tracing then ( + M.tracel "var_eq" "add_eq is_global_var %a = %B\n" d_plainlval lv (is_global_var ask (Lval lv) = Some false); + M.tracel "var_eq" "add_eq interesting %a = %B\n" d_plainexp rv (Exp.interesting rv); + M.tracel "var_eq" "add_eq is_global_var %a = %B\n" d_plainexp rv (is_global_var ask rv = Some false); + M.tracel "var_eq" "add_eq type %a = %B\n" d_plainlval lv ((isArithmeticType lvt && match lvt with | TFloat _ -> false | _ -> true ) || isPointerType lvt); + ); if is_global_var ask (Lval lv) = Some false && Exp.interesting rv && is_global_var ask rv = Some false From f753df5ca377d7000c5519ef6dd9c8264a1057da Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 5 May 2022 12:41:56 +0300 Subject: [PATCH 347/402] Quick fix var_eq interesting for IndexPI --- src/cdomains/exp.ml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/cdomains/exp.ml b/src/cdomains/exp.ml index b4d1890496..3e382642bd 100644 --- a/src/cdomains/exp.ml +++ b/src/cdomains/exp.ml @@ -12,6 +12,8 @@ struct (* TODO: what does interesting mean? *) let rec interesting x = match x with + | BinOp ((PlusPI | IndexPI), e1, e2, _) -> + interesting e1 (* TODO: what about e2? *) | SizeOf _ | SizeOfE _ | SizeOfStr _ From e10102e24532905e813d58db77a37474d93f0345 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 5 May 2022 12:59:26 +0300 Subject: [PATCH 348/402] Add __goblint_assume_join test --- .../51-threadjoins/03-other-assume.c | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 tests/regression/51-threadjoins/03-other-assume.c diff --git a/tests/regression/51-threadjoins/03-other-assume.c b/tests/regression/51-threadjoins/03-other-assume.c new file mode 100644 index 0000000000..71db72fcec --- /dev/null +++ b/tests/regression/51-threadjoins/03-other-assume.c @@ -0,0 +1,34 @@ +//PARAM: --set ana.activated[+] threadJoins +#include +#include + +int g = 10; +int h = 10; +pthread_mutex_t A = PTHREAD_MUTEX_INITIALIZER; + +void *t_fun(void *arg) { + return NULL; +} + +void *t_benign(void *arg) { + pthread_t id2; + pthread_create(&id2, NULL, t_fun, NULL); + __goblint_assume_join(id2, NULL); + // t_fun should be in here + return NULL; +} + +int main(void) { + int t; + + pthread_t id2[10]; + for(int i =0; i < 10;i++) { + pthread_create(&id2[i], NULL, t_benign, NULL); + } + + __goblint_assume_join(id2[2]); + + // t_benign and t_fun should be in here + + return 0; +} From 428a6094571db36b5059b117366a8a0838dd9429 Mon Sep 17 00:00:00 2001 From: Michael Schwarz Date: Thu, 5 May 2022 13:09:49 +0200 Subject: [PATCH 349/402] typo --- src/framework/analyses.ml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/framework/analyses.ml b/src/framework/analyses.ml index f50495f830..2ab7e1019f 100644 --- a/src/framework/analyses.ml +++ b/src/framework/analyses.ml @@ -455,7 +455,7 @@ type increment_data = { new_file: Cil.file; changes: CompareCIL.change_info; - (* Globals for whiche the constraint + (* Globals for which the constraint system unknowns should be restarted *) restarting: VarQuery.t list; } From 4a8aa8575c48f4e224ac7753e4bf2a09e525da95 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 5 May 2022 12:59:45 +0300 Subject: [PATCH 350/402] Implement __goblint_assume_join in threadJoins analysis --- src/analyses/libraryFunctions.ml | 1 + src/analyses/threadJoins.ml | 13 +++++++++++++ 2 files changed, 14 insertions(+) diff --git a/src/analyses/libraryFunctions.ml b/src/analyses/libraryFunctions.ml index be3875c4a7..fd8f7b1219 100644 --- a/src/analyses/libraryFunctions.ml +++ b/src/analyses/libraryFunctions.ml @@ -521,6 +521,7 @@ let invalidate_actions = [ "down_trylock", readsAll; "up", readsAll; "ZSTD_customFree", frees [1]; (* only used with extraspecials *) + "__goblint_assume_join", readsAll; ] (* used by get_invalidate_action to make sure diff --git a/src/analyses/threadJoins.ml b/src/analyses/threadJoins.ml index 4638f6417e..72a91be836 100644 --- a/src/analyses/threadJoins.ml +++ b/src/analyses/threadJoins.ml @@ -45,6 +45,19 @@ struct | _ -> ctx.local (* if multiple possible thread ids are joined, none of them is must joined*) (* Possible improvement: Do the intersection first, things that are must joined in all possibly joined threads are must-joined *) ) + | `Unknown "__goblint_assume_join" -> + let id = List.hd arglist in + let threads = ctx.ask (Queries.EvalThread id) in + if TIDs.is_top threads then + D.bot () (* consider everything joined, D is reversed so bot is All threads *) + else ( + (* elements throws if the thread set is top *) + let threads = TIDs.elements threads in + List.fold_left (fun acc tid -> + let joined = ctx.global tid in + D.union (D.add tid acc) joined + ) ctx.local threads + ) | _ -> ctx.local let query ctx (type a) (q: a Queries.t): a Queries.result = From ed6b2e4b7d5e4addc3b4606f00dce98412306920 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 5 May 2022 14:33:47 +0300 Subject: [PATCH 351/402] Fix MHP.must_be_joined for top joined set --- src/cdomains/mHP.ml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cdomains/mHP.ml b/src/cdomains/mHP.ml index 9b4d773a3c..acf74e4ca9 100644 --- a/src/cdomains/mHP.ml +++ b/src/cdomains/mHP.ml @@ -54,7 +54,7 @@ let exists_definitely_not_started_in_joined (current,created) other_joined = (** Must the thread with thread id other be already joined *) let must_be_joined other joined = if ConcDomain.ThreadSet.is_top joined then - false + true (* top means all threads are joined, so [other] must be as well *) else List.mem other (ConcDomain.ThreadSet.elements joined) From c5cf5265256e88e10b6d57238682252c32bac071 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 5 May 2022 14:34:28 +0300 Subject: [PATCH 352/402] Quick fix realloc read accesses to be shallow --- src/analyses/accessAnalysis.ml | 1 + 1 file changed, 1 insertion(+) diff --git a/src/analyses/accessAnalysis.ml b/src/analyses/accessAnalysis.ml index d19e75b528..9757f39cd3 100644 --- a/src/analyses/accessAnalysis.ml +++ b/src/analyses/accessAnalysis.ml @@ -220,6 +220,7 @@ struct | "memset" | "__builtin_memset" | "__builtin___memset_chk" -> false | "bzero" | "__builtin_bzero" | "explicit_bzero" | "__explicit_bzero_chk" -> false | "__builtin_object_size" -> false + | "realloc" -> false | _ -> true in List.iter (access_one_top ctx `Read reach) (arg_acc `Read); From 2b60af7e495ee5e1a11d8b97ae41a0bc87594932 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 5 May 2022 14:34:48 +0300 Subject: [PATCH 353/402] Add option sem.unknown_function.read.args --- src/analyses/accessAnalysis.ml | 6 +++++- src/util/options.schema.json | 14 ++++++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/src/analyses/accessAnalysis.ml b/src/analyses/accessAnalysis.ml index 9757f39cd3..26b30e5fcb 100644 --- a/src/analyses/accessAnalysis.ml +++ b/src/analyses/accessAnalysis.ml @@ -207,7 +207,11 @@ struct let arg_acc act = match act, LF.get_threadsafe_inv_ac x with | _, Some fnc -> (fnc act arglist) - | `Read, None -> arglist + | `Read, None -> + if get_bool "sem.unknown_function.read.args" then + arglist + else + [] | (`Write | `Free), None -> if get_bool "sem.unknown_function.invalidate.args" then arglist diff --git a/src/util/options.schema.json b/src/util/options.schema.json index 987d8f32a3..82257c8afb 100644 --- a/src/util/options.schema.json +++ b/src/util/options.schema.json @@ -1136,6 +1136,20 @@ } }, "additionalProperties": false + }, + "read": { + "title": "sem.unknown_function.read", + "type": "object", + "properties": { + "args": { + "title": "sem.unknown_function.read.args", + "description": + "Unknown function call reads arguments passed to it", + "type": "boolean", + "default": true + } + }, + "additionalProperties": false } }, "additionalProperties": false From d69de4eef92ba504f59471060abb98ccfffd91e5 Mon Sep 17 00:00:00 2001 From: Michael Schwarz Date: Thu, 5 May 2022 13:35:08 +0200 Subject: [PATCH 354/402] Limit restarting --- src/solvers/td3.ml | 4 ++-- .../11-restart/13-changed_start_state2.c | 13 +++++++++++++ .../11-restart/13-changed_start_state2.json | 18 ++++++++++++++++++ .../11-restart/13-changed_start_state2.patch | 19 +++++++++++++++++++ 4 files changed, 52 insertions(+), 2 deletions(-) create mode 100644 tests/incremental/11-restart/13-changed_start_state2.c create mode 100644 tests/incremental/11-restart/13-changed_start_state2.json create mode 100644 tests/incremental/11-restart/13-changed_start_state2.patch diff --git a/src/solvers/td3.ml b/src/solvers/td3.ml index 18c36dd21d..f0e0ff8646 100644 --- a/src/solvers/td3.ml +++ b/src/solvers/td3.ml @@ -823,7 +823,7 @@ module WP = (* Call side on all globals and functions in the start variables to make sure that changes in the initializers are propagated. * This also destabilizes start functions if their start state changes because of globals that are neither in the start variables nor in the contexts *) List.iter (fun (v,d) -> - if restart_sided then ( + if restart_sided && not restart_only_access then ( match GobList.assoc_eq_opt S.Var.equal v data.st with | Some old_d when not (S.Dom.equal old_d d) -> ignore (Pretty.printf "Destabilizing and restarting changed start var %a\n" S.Var.pretty_trace v); @@ -837,7 +837,7 @@ module WP = side v d ) st; - if restart_sided then ( + if restart_sided && not restart_only_access then ( List.iter (fun (v, _) -> match GobList.assoc_eq_opt S.Var.equal v st with | None -> diff --git a/tests/incremental/11-restart/13-changed_start_state2.c b/tests/incremental/11-restart/13-changed_start_state2.c new file mode 100644 index 0000000000..a239fba4a9 --- /dev/null +++ b/tests/incremental/11-restart/13-changed_start_state2.c @@ -0,0 +1,13 @@ +#include + +int g = 1; + +int main() { + // After the presolve phase, g is in the start state but neither in the context nor in the start variables. + // If the change of the start state of main would not be propagated by the call to side on all start variables, the + // asserts in the incremental run would wrongly fail. Side however only joins with the previous value instead of + // overwriting, therefore the current imprecision. + assert(g == 1); + assert(g != 2); + return 0; +} diff --git a/tests/incremental/11-restart/13-changed_start_state2.json b/tests/incremental/11-restart/13-changed_start_state2.json new file mode 100644 index 0000000000..893cdedc4c --- /dev/null +++ b/tests/incremental/11-restart/13-changed_start_state2.json @@ -0,0 +1,18 @@ +{ + "ana": { + "base": { + "context": { + "int": false + } + } + }, + "incremental": { + "restart": { + "sided": { + "enabled": true, + "only-access": true, + "destab-with-sides": true + } + } + } +} diff --git a/tests/incremental/11-restart/13-changed_start_state2.patch b/tests/incremental/11-restart/13-changed_start_state2.patch new file mode 100644 index 0000000000..0d21dbfc9b --- /dev/null +++ b/tests/incremental/11-restart/13-changed_start_state2.patch @@ -0,0 +1,19 @@ +--- tests/incremental/11-restart/13-changed_start_state2.c ++++ tests/incremental/11-restart/13-changed_start_state2.c +@@ -1,13 +1,13 @@ + #include + +-int g = 1; ++int g = 2; + + int main() { + // After the presolve phase, g is in the start state but neither in the context nor in the start variables. + // If the change of the start state of main would not be propagated by the call to side on all start variables, the + // asserts in the incremental run would wrongly fail. Side however only joins with the previous value instead of + // overwriting, therefore the current imprecision. +- assert(g == 1); +- assert(g != 2); ++ assert(g != 1); ++ assert(g == 2); + return 0; + } From ea05ea88e70b590cc62fb1011564a33aa2b327ea Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 5 May 2022 15:48:09 +0300 Subject: [PATCH 355/402] Fix 02-base/78-realloc-free write-free race --- tests/regression/02-base/78-realloc-free.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/regression/02-base/78-realloc-free.c b/tests/regression/02-base/78-realloc-free.c index a34e112a03..9eeb44cc4a 100644 --- a/tests/regression/02-base/78-realloc-free.c +++ b/tests/regression/02-base/78-realloc-free.c @@ -21,7 +21,7 @@ void test1() { void* test2_f(void *arg) { int *p = arg; - *p = 1; // RACE! + *p = 1; // NORACE return NULL; } @@ -29,7 +29,7 @@ void test2() { int *p = malloc(sizeof(int)); pthread_t id; pthread_create(&id, NULL, test2_f, p); - realloc(p, sizeof(int)); // RACE! + realloc(p, sizeof(int)); // NORACE } void* test3_f(void *arg) { From d09998584d1a38f7a8baab033af4331b692e05e7 Mon Sep 17 00:00:00 2001 From: Michael Schwarz Date: Thu, 5 May 2022 16:10:01 +0200 Subject: [PATCH 356/402] Allow for actual imprecision --- tests/incremental/11-restart/13-changed_start_state2.patch | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/incremental/11-restart/13-changed_start_state2.patch b/tests/incremental/11-restart/13-changed_start_state2.patch index 0d21dbfc9b..2c08def40c 100644 --- a/tests/incremental/11-restart/13-changed_start_state2.patch +++ b/tests/incremental/11-restart/13-changed_start_state2.patch @@ -13,7 +13,7 @@ // overwriting, therefore the current imprecision. - assert(g == 1); - assert(g != 2); -+ assert(g != 1); -+ assert(g == 2); ++ assert(g != 1); //TODO ++ assert(g == 2); //TODO return 0; } From 7e5ab0a4fc4210dbd8be807207712aa8c5b92061 Mon Sep 17 00:00:00 2001 From: Vesal Vojdani Date: Thu, 5 May 2022 19:26:47 +0000 Subject: [PATCH 357/402] Correct strcat; add strncat. --- src/analyses/libraryFunctions.ml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/analyses/libraryFunctions.ml b/src/analyses/libraryFunctions.ml index fd8f7b1219..b1d06d6b15 100644 --- a/src/analyses/libraryFunctions.ml +++ b/src/analyses/libraryFunctions.ml @@ -271,6 +271,7 @@ let invalidate_actions = [ "strlen", readsAll;(*safe*) "strncmp", readsAll;(*safe*) "strncpy", writes [1];(*keep [1]*) + "strncat", writes [1];(*keep [1]*) "strstr", readsAll;(*safe*) "strdup", readsAll;(*safe*) "toupper", readsAll;(*safe*) @@ -341,7 +342,7 @@ let invalidate_actions = [ "strcpy", writes [1];(*keep [1]*) "__builtin___strcpy", writes [1];(*keep [1]*) "__builtin___strcpy_chk", writes [1];(*keep [1]*) - "strcat", writes [2];(*keep [2]*) + "strcat", writes [1];(*keep [1]*) "getpgrp", readsAll;(*safe*) "umount2", readsAll;(*safe*) "memchr", readsAll;(*safe*) From d660f1aa1a18a1e959ea095bec01f4114f55bd4d Mon Sep 17 00:00:00 2001 From: Vesal Vojdani Date: Fri, 6 May 2022 08:11:37 +0000 Subject: [PATCH 358/402] Add a few more libraryfuns. --- src/analyses/libraryFunctions.ml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/analyses/libraryFunctions.ml b/src/analyses/libraryFunctions.ml index b1d06d6b15..a0eeb8d161 100644 --- a/src/analyses/libraryFunctions.ml +++ b/src/analyses/libraryFunctions.ml @@ -315,6 +315,9 @@ let invalidate_actions = [ "pthread_attr_setdetachstate", writesAll;(*unsafe*) "pthread_attr_setstacksize", writesAll;(*unsafe*) "pthread_attr_setscope", writesAll;(*unsafe*) + "pthread_attr_getdetachstate", readsAll;(*safe*) + "pthread_attr_getstacksize", readsAll;(*safe*) + "pthread_attr_getscope", readsAll;(*safe*) "pthread_cond_init", readsAll; (*safe*) "pthread_cond_wait", readsAll; (*safe*) "pthread_cond_signal", readsAll;(*safe*) @@ -343,6 +346,7 @@ let invalidate_actions = [ "__builtin___strcpy", writes [1];(*keep [1]*) "__builtin___strcpy_chk", writes [1];(*keep [1]*) "strcat", writes [1];(*keep [1]*) + "strtok", readsAll;(*safe*) "getpgrp", readsAll;(*safe*) "umount2", readsAll;(*safe*) "memchr", readsAll;(*safe*) @@ -377,6 +381,7 @@ let invalidate_actions = [ "fputs", readsAll;(*safe*) "fputc", readsAll;(*safe*) "fseek", writes[1]; + "rewind", writesAll; "fileno", readsAll; "ferror", readsAll; "ftell", readsAll; From 2f66be2185c4f333b91e6f99c17d0c994f88708a Mon Sep 17 00:00:00 2001 From: Vesal Vojdani Date: Fri, 6 May 2022 12:52:52 +0000 Subject: [PATCH 359/402] Add minimal-ish example of what causes deadcode in smtprc. --- .../regression/03-practical/27-charptr_null.c | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 tests/regression/03-practical/27-charptr_null.c diff --git a/tests/regression/03-practical/27-charptr_null.c b/tests/regression/03-practical/27-charptr_null.c new file mode 100644 index 0000000000..23896b8e25 --- /dev/null +++ b/tests/regression/03-practical/27-charptr_null.c @@ -0,0 +1,33 @@ +#include +#include +#include +#include + +struct options +{ + char *ip_range; +}; + +struct options o; + +int get_ip_range(int *iprange) +{ + char *r = iprange; + + while (*r++) + { + *r = '\0'; + assert(1); + } + + return (0); +} + +int main() +{ + char *optarg = "was from unistd.h"; + o.ip_range = malloc((strlen(optarg) + 1) * sizeof(char)); + strncpy(o.ip_range, optarg, strlen(optarg)); + o.ip_range[strlen(optarg)] = '\0'; + get_ip_range(o.ip_range); +} \ No newline at end of file From 69fd28b89a7ba14812bf54546485978207496a40 Mon Sep 17 00:00:00 2001 From: Vesal Vojdani Date: Fri, 6 May 2022 15:46:26 +0000 Subject: [PATCH 360/402] Self-documenting code for arinc deobfuscation. --- src/analyses/base.ml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/analyses/base.ml b/src/analyses/base.ml index 7f8d8c10af..97cf1d6b96 100644 --- a/src/analyses/base.ml +++ b/src/analyses/base.ml @@ -2174,9 +2174,9 @@ struct set ~ctx:(Some ctx) (Analyses.ask_of_ctx ctx) gs st dest_a dest_typ value | _, _ -> failwith "strange bzero arguments" end - | `Unknown "F59" (* strcpy *) - | `Unknown "F60" (* strncpy *) - | `Unknown "F63" (* memcpy *) + | `Unknown ("F59" | "strcpy") + | `Unknown ("F60" | "strncpy") + | `Unknown ("F63" | "memcpy") -> begin match args with | [dst; src] From 99ed43e958ac7ca4dcb090e5d30a549557231809 Mon Sep 17 00:00:00 2001 From: Vesal Vojdani Date: Fri, 6 May 2022 15:51:58 +0000 Subject: [PATCH 361/402] Set memcpy and strcpy to top; these can overwrite partially. --- src/analyses/base.ml | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/src/analyses/base.ml b/src/analyses/base.ml index 97cf1d6b96..d66b46e237 100644 --- a/src/analyses/base.ml +++ b/src/analyses/base.ml @@ -2188,15 +2188,12 @@ struct (* | _ -> ignore @@ Pretty.printf "strcpy: dst %a may point to anything!\n" d_exp dst; *) (* ctx.local *) (* end *) - let rec get_lval exp = match stripCasts exp with - | Lval x | AddrOf x | StartOf x -> x - | BinOp (PlusPI, e, i, _) - | BinOp (MinusPI, e, i, _) -> get_lval e - | x -> - ignore @@ Pretty.printf "strcpy: dst is %a!\n" d_plainexp dst; - failwith "strcpy: expecting first argument to be a pointer!" - in - assign ctx (get_lval dst) src + let dest_lval = mkMem ~addr:(Cil.stripCasts dst) ~off:NoOffset in + let dest_a = eval_lv (Analyses.ask_of_ctx ctx) gs st dest_lval in + (* let dest_typ = Cilfacade.typeOfLval dest_lval in *) + let dest_typ = AD.get_type dest_a in + let value = VD.top_value dest_typ in + set ~ctx:(Some ctx) (Analyses.ask_of_ctx ctx) gs st dest_a dest_typ value | _ -> failwith "strcpy arguments are strange/complicated." end | `Unknown "F1" -> From 089cc2ae8e0a1ab2374af102ff312600b5a1e8bf Mon Sep 17 00:00:00 2001 From: Vesal Vojdani Date: Fri, 6 May 2022 16:10:08 +0000 Subject: [PATCH 362/402] Extract addr_type_of_exp. --- src/analyses/base.ml | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/src/analyses/base.ml b/src/analyses/base.ml index d66b46e237..69ddd3e787 100644 --- a/src/analyses/base.ml +++ b/src/analyses/base.ml @@ -2134,6 +2134,11 @@ struct invalidate ~ctx (Analyses.ask_of_ctx ctx) ctx.global st [Cil.mkAddrOrStartOf lv] | None -> st in + let addr_type_of_exp exp = + let lval = mkMem ~addr:(Cil.stripCasts exp) ~off:NoOffset in + let addr = eval_lv (Analyses.ask_of_ctx ctx) ctx.global ctx.local lval in + (addr, AD.get_type addr) + in let forks = forkfun ctx lv f args in if M.tracing then if not (List.is_empty forks) then M.tracel "spawn" "Base.special %s: spawning functions %a\n" f.vname (d_list "," d_varinfo) (List.map BatTuple.Tuple3.second forks); List.iter (BatTuple.Tuple3.uncurry ctx.spawn) forks; @@ -2146,10 +2151,7 @@ struct | ("memset" | "__builtin_memset"), [dest; ch; count] -> (* TODO: check count *) let eval_ch = eval_rv (Analyses.ask_of_ctx ctx) gs st ch in - let dest_lval = mkMem ~addr:(Cil.stripCasts dest) ~off:NoOffset in - let dest_a = eval_lv (Analyses.ask_of_ctx ctx) gs st dest_lval in - (* let dest_typ = Cilfacade.typeOfLval dest_lval in *) - let dest_typ = AD.get_type dest_a in (* TODO: what is the right way? *) + let dest_a, dest_typ = addr_type_of_exp dest in let value = match eval_ch with | `Int i when ID.to_int i = Some Z.zero -> @@ -2166,10 +2168,7 @@ struct | "__explicit_bzero_chk", [dest; count; _ (* dest_size *)] | ("bzero" | "__builtin_bzero" | "explicit_bzero"), [dest; count] -> (* TODO: check count *) - let dest_lval = mkMem ~addr:(Cil.stripCasts dest) ~off:NoOffset in - let dest_a = eval_lv (Analyses.ask_of_ctx ctx) gs st dest_lval in - (* let dest_typ = Cilfacade.typeOfLval dest_lval in *) - let dest_typ = AD.get_type dest_a in (* TODO: what is the right way? *) + let dest_a, dest_typ = addr_type_of_exp dest in let value = VD.zero_init_value dest_typ in set ~ctx:(Some ctx) (Analyses.ask_of_ctx ctx) gs st dest_a dest_typ value | _, _ -> failwith "strange bzero arguments" @@ -2188,10 +2187,7 @@ struct (* | _ -> ignore @@ Pretty.printf "strcpy: dst %a may point to anything!\n" d_exp dst; *) (* ctx.local *) (* end *) - let dest_lval = mkMem ~addr:(Cil.stripCasts dst) ~off:NoOffset in - let dest_a = eval_lv (Analyses.ask_of_ctx ctx) gs st dest_lval in - (* let dest_typ = Cilfacade.typeOfLval dest_lval in *) - let dest_typ = AD.get_type dest_a in + let dest_a, dest_typ = addr_type_of_exp dst in let value = VD.top_value dest_typ in set ~ctx:(Some ctx) (Analyses.ask_of_ctx ctx) gs st dest_a dest_typ value | _ -> failwith "strcpy arguments are strange/complicated." From 577f6f33e83d9d3f64974dbe06c7e68374a679eb Mon Sep 17 00:00:00 2001 From: Michael Schwarz Date: Wed, 11 May 2022 10:27:23 +0200 Subject: [PATCH 363/402] Add test that's unsound because of __goblint_assume_join(...) --- tests/regression/46-apron2/03-other-assume.c | 38 ++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 tests/regression/46-apron2/03-other-assume.c diff --git a/tests/regression/46-apron2/03-other-assume.c b/tests/regression/46-apron2/03-other-assume.c new file mode 100644 index 0000000000..066ddac122 --- /dev/null +++ b/tests/regression/46-apron2/03-other-assume.c @@ -0,0 +1,38 @@ +//PARAM: --set ana.activated[+] apron --set ana.path_sens[+] threadflag --set ana.activated[+] threadJoins --sets ana.apron.privatization mutex-meet-tid +#include +#include + +int g = 10; +int h = 10; +pthread_mutex_t A = PTHREAD_MUTEX_INITIALIZER; + +void *t_fun(void *arg) { + return NULL; +} + +void *t_benign(void *arg) { + pthread_t id2; + pthread_create(&id2, NULL, t_fun, NULL); + __goblint_assume_join(id2, NULL); + // t_fun should be in here + + g = 7; + + return NULL; +} + +int main(void) { + int t; + + pthread_t id2[10]; + for(int i =0; i < 10;i++) { + pthread_create(&id2[i], NULL, t_benign, NULL); + } + + __goblint_assume_join(id2[2]); + // t_benign and t_fun should be in here + + assert(g==h); //FAIL + + return 0; +} From 76f9b29884da7c8ec329979d35db92f4838d6a02 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 12 May 2022 12:09:20 +0300 Subject: [PATCH 364/402] Add threadJoins test where recreated threads should be removed from must-join set --- .../51-threadjoins/04-assume-recreate.c | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 tests/regression/51-threadjoins/04-assume-recreate.c diff --git a/tests/regression/51-threadjoins/04-assume-recreate.c b/tests/regression/51-threadjoins/04-assume-recreate.c new file mode 100644 index 0000000000..8424303e97 --- /dev/null +++ b/tests/regression/51-threadjoins/04-assume-recreate.c @@ -0,0 +1,23 @@ +//PARAM: --set ana.activated[+] threadJoins --disable ana.thread.include-node --set ana.thread.domain plain +#include +#include + +int g = 0; + +void *t_fun(void *arg) { + g++; // RACE! + return NULL; +} + +int main() { + pthread_t id; + pthread_create(&id, NULL, t_fun, NULL); + + __goblint_assume_join(id); // should add to must-joined + + pthread_create(&id, NULL, t_fun, NULL); // should remove from must-joined again + + g++; // RACE! + + return 0; +} From 84a98bfde82b70e21609041e4263a844122cd19d Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 12 May 2022 12:14:24 +0300 Subject: [PATCH 365/402] Make threadspawn remove must-joined threads --- src/analyses/threadJoins.ml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/analyses/threadJoins.ml b/src/analyses/threadJoins.ml index 72a91be836..024cfe41be 100644 --- a/src/analyses/threadJoins.ml +++ b/src/analyses/threadJoins.ml @@ -60,6 +60,13 @@ struct ) | _ -> ctx.local + let threadspawn ctx lval f args fctx = + match ThreadId.get_current (Analyses.ask_of_ctx fctx) with + | `Lifted tid -> + D.remove tid ctx.local + | _ -> + ctx.local + let query ctx (type a) (q: a Queries.t): a Queries.result = match q with | Queries.MustJoinedThreads -> (ctx.local:ConcDomain.MustThreadSet.t) (* type annotation needed to avoid "would escape the scope of its equation" *) From b09b1fd4ea29082968836e5166b38b5fc016e9ff Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 12 May 2022 12:16:35 +0300 Subject: [PATCH 366/402] Add SKIP to 36-apron2/03-other-assume like other Apron tests --- tests/regression/46-apron2/03-other-assume.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/regression/46-apron2/03-other-assume.c b/tests/regression/46-apron2/03-other-assume.c index 066ddac122..e02d33d386 100644 --- a/tests/regression/46-apron2/03-other-assume.c +++ b/tests/regression/46-apron2/03-other-assume.c @@ -1,4 +1,4 @@ -//PARAM: --set ana.activated[+] apron --set ana.path_sens[+] threadflag --set ana.activated[+] threadJoins --sets ana.apron.privatization mutex-meet-tid +// SKIP PARAM: --set ana.activated[+] apron --set ana.path_sens[+] threadflag --set ana.activated[+] threadJoins --sets ana.apron.privatization mutex-meet-tid #include #include From f2b8673e53e32ac1ef953467abb3d9bcf7cf2667 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 12 May 2022 12:27:40 +0300 Subject: [PATCH 367/402] Fix __goblint_assume_join with Apron mutex-meet-tid privatization --- src/analyses/apron/apronAnalysis.apron.ml | 3 ++ src/analyses/apron/apronPriv.apron.ml | 49 +++++++++++++++-------- 2 files changed, 35 insertions(+), 17 deletions(-) diff --git a/src/analyses/apron/apronAnalysis.apron.ml b/src/analyses/apron/apronAnalysis.apron.ml index b1ef74bd4d..5ffd4b67a1 100644 --- a/src/analyses/apron/apronAnalysis.apron.ml +++ b/src/analyses/apron/apronAnalysis.apron.ml @@ -323,6 +323,9 @@ struct | Some lv -> invalidate_one st' lv | None -> st' ) + | `Unknown "__goblint_assume_join" -> + let id = List.hd args in + Priv.thread_join ~force:true ask ctx.global id st | _ -> let ask = Analyses.ask_of_ctx ctx in let invalidate_one st lv = diff --git a/src/analyses/apron/apronPriv.apron.ml b/src/analyses/apron/apronPriv.apron.ml index 49ef99302f..83299dad58 100644 --- a/src/analyses/apron/apronPriv.apron.ml +++ b/src/analyses/apron/apronPriv.apron.ml @@ -37,7 +37,7 @@ module type S = val enter_multithreaded: Q.ask -> (V.t -> G.t) -> (V.t -> G.t -> unit) -> apron_components_t -> apron_components_t val threadenter: Q.ask -> (V.t -> G.t) -> apron_components_t -> apron_components_t - val thread_join: Q.ask -> (V.t -> G.t) -> Cil.exp -> apron_components_t -> apron_components_t + val thread_join: ?force:bool -> Q.ask -> (V.t -> G.t) -> Cil.exp -> apron_components_t -> apron_components_t val thread_return: Q.ask -> (V.t -> G.t) -> (V.t -> G.t -> unit) -> ThreadIdDomain.Thread.t -> apron_components_t -> apron_components_t val iter_sys_vars: (V.t -> G.t) -> VarQuery.t -> V.t VarQuery.f -> unit (** [Queries.IterSysVars] for apron. *) @@ -62,7 +62,7 @@ struct let lock ask getg st m = st let unlock ask getg sideg st m = st - let thread_join ask getg exp st = st + let thread_join ?(force=false) ask getg exp st = st let thread_return ask getg sideg tid st = st let sync ask getg sideg st reason = st @@ -270,7 +270,7 @@ struct {apr = apr_local'; priv = (p', w')} - let thread_join ask getg exp st = st + let thread_join ?(force=false) ask getg exp st = st let thread_return ask getg sideg tid st = st let sync ask getg sideg (st: apron_components_t) reason = @@ -461,7 +461,7 @@ struct let apr_local = remove_globals_unprotected_after_unlock ask m apr in {st with apr = apr_local} - let thread_join ask getg exp st = st + let thread_join ?(force=false) ask getg exp st = st let thread_return ask getg sideg tid st = st let sync ask getg sideg (st: apron_components_t) reason = @@ -983,22 +983,37 @@ struct let l' = L.add lm apr_side l in {apr = apr_local; priv = (w',LMust.add lm lmust,l')} - let thread_join (ask:Q.ask) getg exp (st: apron_components_t) = + let thread_join ?(force=false) (ask:Q.ask) getg exp (st: apron_components_t) = let w,lmust,l = st.priv in let tids = ask.f (Q.EvalThread exp) in - if ConcDomain.ThreadSet.is_top tids then - st (* TODO: why needed? *) + if force then ( + if ConcDomain.ThreadSet.is_top tids then + failwith "TODO" + else ( + (* fold throws if the thread set is top *) + let (lmust', l') = ConcDomain.ThreadSet.fold (fun tid (lmust, l) -> + let lmust',l' = G.thread (getg (V.thread tid)) in + (LMust.union lmust' lmust, L.join l l') + ) tids (lmust, l) + in + {st with priv = (w, lmust', l')} + ) + ) else ( - (* elements throws if the thread set is top *) - let tids = ConcDomain.ThreadSet.elements tids in - match tids with - | [tid] -> - let lmust',l' = G.thread (getg (V.thread tid)) in - {st with priv = (w, LMust.union lmust' lmust, L.join l l')} - | _ -> - (* To match the paper more closely, one would have to join in the non-definite case too *) - (* Given how we handle lmust (for initialization), doing this might actually be beneficial given that it grows lmust *) - st + if ConcDomain.ThreadSet.is_top tids then + st (* TODO: why needed? *) + else ( + (* elements throws if the thread set is top *) + let tids = ConcDomain.ThreadSet.elements tids in + match tids with + | [tid] -> + let lmust',l' = G.thread (getg (V.thread tid)) in + {st with priv = (w, LMust.union lmust' lmust, L.join l l')} + | _ -> + (* To match the paper more closely, one would have to join in the non-definite case too *) + (* Given how we handle lmust (for initialization), doing this might actually be beneficial given that it grows lmust *) + st + ) ) let thread_return ask getg sideg tid (st: apron_components_t) = From d5a0c27e3aec3d88621241e5193a5810d0d67370 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 12 May 2022 12:53:34 +0300 Subject: [PATCH 368/402] Add __goblint_assume_join to annotating docs --- docs/user-guide/annotating.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/docs/user-guide/annotating.md b/docs/user-guide/annotating.md index 17698e6eda..db4749ccbb 100644 --- a/docs/user-guide/annotating.md +++ b/docs/user-guide/annotating.md @@ -25,3 +25,11 @@ The following string arguments are supported: 3. `base.non-ptr`/`base.no-non-ptr` to override the `ana.base.context.non-ptr` option. 4. `apron.context`/`apron.no-context` to override the `ana.apron.context` option. 5. `widen`/`no-widen` to override the `ana.context.widen` option. + + +## Functions +Goblint-specific functions can be called in the code, where they assist the analyzer but have no runtime effect. + +* `__goblint_assume_join(id)` is like `pthread_join(id)`, but considers the given thread IDs must-joined even if Goblint cannot, e.g. due to non-uniqueness. + Notably, this annotation can be used after a threads joining loop to make the assumption that the loop correctly joined all those threads. + _Misuse of this annotation can cause unsoundness._ From a4db1a0e0a897b2b82793b8a8f944370ac42b52f Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Fri, 13 May 2022 10:04:15 +0300 Subject: [PATCH 369/402] Add assume join test with unknown thread ID --- .../51-threadjoins/05-assume-unknown.c | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 tests/regression/51-threadjoins/05-assume-unknown.c diff --git a/tests/regression/51-threadjoins/05-assume-unknown.c b/tests/regression/51-threadjoins/05-assume-unknown.c new file mode 100644 index 0000000000..d870918240 --- /dev/null +++ b/tests/regression/51-threadjoins/05-assume-unknown.c @@ -0,0 +1,21 @@ +//PARAM: --set ana.activated[+] threadJoins +#include +#include + +int g = 0; + +void *t_fun(void *arg) { + g++; // RACE! + return NULL; +} + +int main() { + pthread_t id, id2; + pthread_create(&id, NULL, t_fun, NULL); + + __goblint_assume_join(id2); // joining unknown thread ID, shouldn't make joined set All threads + + g++; // RACE! + + return 0; +} From e6e33b290d54a126774097a6b16364ccf43e60f6 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Fri, 13 May 2022 10:06:48 +0300 Subject: [PATCH 370/402] Change assume join behavior with unknown thread ID --- src/analyses/apron/apronPriv.apron.ml | 2 +- src/analyses/threadJoins.ml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/analyses/apron/apronPriv.apron.ml b/src/analyses/apron/apronPriv.apron.ml index 83299dad58..1b8a71f4c4 100644 --- a/src/analyses/apron/apronPriv.apron.ml +++ b/src/analyses/apron/apronPriv.apron.ml @@ -988,7 +988,7 @@ struct let tids = ask.f (Q.EvalThread exp) in if force then ( if ConcDomain.ThreadSet.is_top tids then - failwith "TODO" + st (* don't consider anything more joined, matches threadJoins analysis *) else ( (* fold throws if the thread set is top *) let (lmust', l') = ConcDomain.ThreadSet.fold (fun tid (lmust, l) -> diff --git a/src/analyses/threadJoins.ml b/src/analyses/threadJoins.ml index 024cfe41be..c85061de71 100644 --- a/src/analyses/threadJoins.ml +++ b/src/analyses/threadJoins.ml @@ -49,7 +49,7 @@ struct let id = List.hd arglist in let threads = ctx.ask (Queries.EvalThread id) in if TIDs.is_top threads then - D.bot () (* consider everything joined, D is reversed so bot is All threads *) + ctx.local (* don't consider everything joined, because would be confusing to have All threads unsoundly joined due to imprecision *) else ( (* elements throws if the thread set is top *) let threads = TIDs.elements threads in From 9d71c07bd9738bb5cbd7173e4fc7e15632a376fd Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Fri, 13 May 2022 13:24:54 +0300 Subject: [PATCH 371/402] Revert "Merge pull request #364 from goblint/td3-solve-tf-abort" This reverts commit 8cb50d470eaba036999922c4ef4ad6ddd1630528, reversing changes made to b72dfe473bce74d8769576895a90eb82392bfd00. Includes reverting of additional fixes later made to abort on the interactive branch. --- scripts/creduce-abort-verify.sh | 19 -- src/framework/constraints.ml | 23 +- src/maingoblint.ml | 3 +- src/solvers/generic.ml | 3 - src/solvers/td3.ml | 225 +++--------------- src/util/goblintutil.ml | 1 - src/util/options.schema.json | 12 - .../11-restart/48-local-wpoint-funcall.json | 4 +- tests/incremental/12-abort/01-abort_aget.c | 13 - tests/incremental/12-abort/01-abort_aget.json | 44 ---- .../incremental/12-abort/01-abort_aget.patch | 11 - tests/incremental/12-abort/02-abort-smtprc.c | 36 --- .../incremental/12-abort/02-abort-smtprc.json | 44 ---- .../12-abort/02-abort-smtprc.patch | 11 - tests/regression/04-mutex/80-td3-self-abort.c | 15 -- .../29-svcomp/27-td3-front-via-destab-infl.c | 42 ---- .../21-restart_abort_aget.c | 23 -- .../46-apron2/01-td3-self-abort-complex.c | 30 --- 18 files changed, 41 insertions(+), 518 deletions(-) delete mode 100755 scripts/creduce-abort-verify.sh delete mode 100644 tests/incremental/12-abort/01-abort_aget.c delete mode 100644 tests/incremental/12-abort/01-abort_aget.json delete mode 100644 tests/incremental/12-abort/01-abort_aget.patch delete mode 100644 tests/incremental/12-abort/02-abort-smtprc.c delete mode 100644 tests/incremental/12-abort/02-abort-smtprc.json delete mode 100644 tests/incremental/12-abort/02-abort-smtprc.patch delete mode 100644 tests/regression/04-mutex/80-td3-self-abort.c delete mode 100644 tests/regression/29-svcomp/27-td3-front-via-destab-infl.c delete mode 100644 tests/regression/34-localwn_restart/21-restart_abort_aget.c delete mode 100644 tests/regression/46-apron2/01-td3-self-abort-complex.c diff --git a/scripts/creduce-abort-verify.sh b/scripts/creduce-abort-verify.sh deleted file mode 100755 index 3bbb70c587..0000000000 --- a/scripts/creduce-abort-verify.sh +++ /dev/null @@ -1,19 +0,0 @@ -#!/usr/bin/env bash - -set -e - -gcc -c -Werror=implicit-function-declaration ./abort-verify.c - -GOBLINTDIR="/mnt/goblint-svcomp/sv-comp/goblint" -OPTS="--conf $GOBLINTDIR/conf/svcomp.json --enable solvers.td3.abort --enable solvers.td3.abort-verify --sets ana.specification /mnt/goblint-svcomp/benchexec/sv-benchmarks/c/properties/unreach-call.prp --sets exp.architecture 64bit ./abort-verify.c" -INTERESTING="TD3 abort verify: should not abort" -OUTDIR="creduce-abort-verify" - - -mkdir -p $OUTDIR - -LOG="$OUTDIR/out.log" -$GOBLINTDIR/goblint $OPTS -v --enable dbg.debug &> $LOG || true -grep -F "Function definition missing" $LOG && exit 1 - -grep -F "$INTERESTING" $LOG diff --git a/src/framework/constraints.ml b/src/framework/constraints.ml index cf85bcb73c..f851afe7bb 100644 --- a/src/framework/constraints.ml +++ b/src/framework/constraints.ml @@ -458,7 +458,7 @@ module FromSpec (S:Spec) (Cfg:CfgBackward) (I: Increment) and module GVar = GVarF (S.V) and module D = S.D and module G = GVarG (S.G) (S.C) - val tf : MyCFG.node * S.C.t -> (Cil.location * MyCFG.edge) list * MyCFG.node -> D.t -> ((MyCFG.node * S.C.t) -> S.D.t) -> (MyCFG.node * S.C.t -> S.D.t -> unit) -> (GVar.t -> G.t) -> (GVar.t -> G.t -> unit) -> D.t + val tf : MyCFG.node * S.C.t -> (Cil.location * MyCFG.edge) list * MyCFG.node -> ((MyCFG.node * S.C.t) -> S.D.t) -> (MyCFG.node * S.C.t -> S.D.t -> unit) -> (GVar.t -> G.t) -> (GVar.t -> G.t -> unit) -> D.t end = struct @@ -705,12 +705,12 @@ struct d ) - let tf (v,c) (edges, u) pval getl sidel getg sideg = - (* let pval = getl (u,c) in *) + let tf (v,c) (edges, u) getl sidel getg sideg = + let pval = getl (u,c) in let _, locs = List.fold_right (fun (f,e) (t,xs) -> f, (f,t)::xs) edges (Node.location v,[]) in List.fold_left2 (|>) pval (List.map (tf (v,Obj.repr (fun () -> c)) getl sidel getg sideg u) edges) locs - let tf (v,c) (e,u) pval getl sidel getg sideg = + let tf (v,c) (e,u) getl sidel getg sideg = let old_node = !current_node in let old_context = !M.current_context in current_node := Some u; @@ -719,7 +719,7 @@ struct current_node := old_node; M.current_context := old_context ) (fun () -> - let d = tf (v,c) (e,u) pval getl sidel getg sideg in + let d = tf (v,c) (e,u) getl sidel getg sideg in d ) @@ -729,16 +729,14 @@ struct None | _ -> let tf getl sidel getg sideg = - let get_pval (_, u) = getl (u, c) in - let tf' eu pval = tf (v,c) eu pval getl sidel getg sideg in + let tf' eu = tf (v,c) eu getl sidel getg sideg in match NodeH.find_option CfgTools.node_scc_global v with | Some scc when NodeH.mem scc.prev v && NodeH.length scc.prev = 1 -> (* Limited to loops with only one entry node. Otherwise unsound as is. *) (* TODO: Is it possible to do soundly for multi-entry loops? *) let stricts = NodeH.find_default scc.prev v [] in - let pvals_stricts = List.map get_pval stricts in (* get pvals before executing any tf to maximize abort *) - let xs_stricts = List.map2 tf' stricts pvals_stricts in + let xs_stricts = List.map tf' stricts in if List.for_all S.D.is_bot xs_stricts then S.D.bot () else @@ -746,13 +744,10 @@ struct let equal = [%eq: (CilType.Location.t * Edge.t) list * Node.t] in let is_strict eu = List.exists (equal eu) stricts in let non_stricts = List.filter (neg is_strict) (Cfg.prev v) in - let pvals_non_stricts = List.map get_pval non_stricts in (* get pvals before executing any tf to maximize abort *) - let xs_non_stricts = List.map2 tf' non_stricts pvals_non_stricts in + let xs_non_stricts = List.map tf' non_stricts in List.fold_left S.D.join xs_strict xs_non_stricts | _ -> - let prevs = Cfg.prev v in - let pvals = List.map get_pval prevs in (* get pvals before executing any tf to maximize abort *) - let xs = List.map2 tf' prevs pvals in + let xs = List.map tf' (Cfg.prev v) in List.fold_left S.D.join (S.D.bot ()) xs in Some tf diff --git a/src/maingoblint.ml b/src/maingoblint.ml index a28a1acc5c..ce3ce95cd6 100644 --- a/src/maingoblint.ml +++ b/src/maingoblint.ml @@ -388,7 +388,7 @@ let preprocess_and_merge () = preprocess_files () |> merge_preprocessed let do_stats () = if get_bool "printstats" then ( print_newline (); - ignore (Pretty.printf "vars = %d evals = %d narrow_reuses = %d aborts = %d\n" !Goblintutil.vars !Goblintutil.evals !Goblintutil.narrow_reuses !Goblintutil.aborts); + ignore (Pretty.printf "vars = %d evals = %d narrow_reuses = %d\n" !Goblintutil.vars !Goblintutil.evals !Goblintutil.narrow_reuses); print_newline (); Stats.print (Messages.get_out "timing" Legacy.stderr) "Timings:\n"; flush_all () @@ -398,7 +398,6 @@ let reset_stats () = Goblintutil.vars := 0; Goblintutil.evals := 0; Goblintutil.narrow_reuses := 0; - Goblintutil.aborts := 0; Stats.reset SoftwareTimer (** Perform the analysis over the merged AST. *) diff --git a/src/solvers/generic.ml b/src/solvers/generic.ml index fdc545ac0d..86b88960cc 100644 --- a/src/solvers/generic.ml +++ b/src/solvers/generic.ml @@ -78,9 +78,6 @@ struct incr Goblintutil.evals; if (get_bool "dbg.solver-progress") then (incr stack_d; print_int !stack_d; flush stdout) - let abort_rhs_event x = - incr Goblintutil.aborts - let update_var_event x o n = if tracing then increase x; if full_trace || ((not (Dom.is_bot o)) && Option.is_some !max_var && Var.equal (Option.get !max_var) x) then begin diff --git a/src/solvers/td3.ml b/src/solvers/td3.ml index 11ffece69a..b45d8cd04a 100644 --- a/src/solvers/td3.ml +++ b/src/solvers/td3.ml @@ -104,15 +104,12 @@ module WP = Some f' end - exception AbortEq - let solve box st vs data = let term = GobConfig.get_bool "solvers.td3.term" in let side_widen = GobConfig.get_string "solvers.td3.side_widen" in let space = GobConfig.get_bool "solvers.td3.space" in let cache = GobConfig.get_bool "solvers.td3.space_cache" in let called = HM.create 10 in - let called_changed = HM.create 10 in let infl = data.infl in let sides = data.sides in @@ -151,14 +148,6 @@ module WP = let var_messages = data.var_messages in let rho_write = data.rho_write in - let abort = GobConfig.get_bool "solvers.td3.abort" in - let destab_infl = HM.create 10 in - let destab_front = HM.create 10 in - let destab_dep = HM.create 10 in - - let abort_verify = GobConfig.get_bool "solvers.td3.abort-verify" in - let prev_dep_vals = HM.create 10 in - (* Tracks dependencies between an unknown and the things it depends on *) let dep = data.dep in @@ -175,25 +164,14 @@ module WP = let cache_sizes = ref [] in - let trace_called () = - if tracing then ( - let called_pretty () called = - HM.fold (fun x _ acc -> Pretty.dprintf "%a\n %a" S.Var.pretty_trace x Pretty.insert acc) called Pretty.nil - in - trace "sol2" "called:\n %a\n" called_pretty called - ) - in - let vs_pretty () vs = - VS.fold (fun x acc -> Pretty.dprintf "%a, %a" S.Var.pretty_trace x Pretty.insert acc) vs Pretty.nil - in - let add_infl y x = if tracing then trace "sol2" "add_infl %a %a\n" S.Var.pretty_trace y S.Var.pretty_trace x; HM.replace infl y (VS.add x (try HM.find infl y with Not_found -> VS.empty)); HM.replace dep x (VS.add y (HM.find_default dep x VS.empty)); in let add_sides y x = HM.replace sides y (VS.add x (try HM.find sides y with Not_found -> VS.empty)) in - let destabilize_ref: (?front:bool -> S.v -> unit) ref = ref (fun ?front _ -> failwith "no destabilize yet") in + + let destabilize_ref: (S.v -> unit) ref = ref (fun _ -> failwith "no destabilize yet") in let destabilize x = !destabilize_ref x in (* must be eta-expanded to use changed destabilize_ref *) let rec destabilize_vs x = (* TODO remove? Only used for side_widen cycle. *) @@ -206,9 +184,8 @@ module WP = HM.remove superstable y; HM.mem called y || destabilize_vs y || b || was_stable && List.mem y vs ) w false - and solve ?reuse_eq ?(abortable=true) x phase (changed: bool): bool = - if tracing then trace "sol2" "solve %a, phase: %s, changed: %b, abortable: %b, called: %b, stable: %b\n" S.Var.pretty_trace x (match phase with Widen -> "Widen" | Narrow -> "Narrow") changed abortable (HM.mem called x) (HM.mem stable x); - trace_called (); + and solve ?reuse_eq x phase = + if tracing then trace "sol2" "solve %a, phase: %s, called: %b, stable: %b\n" S.Var.pretty_trace x (match phase with Widen -> "Widen" | Narrow -> "Narrow") (HM.mem called x) (HM.mem stable x); init x; assert (S.system x <> None); if not (HM.mem called x || HM.mem stable x) then ( @@ -222,80 +199,17 @@ module WP = Then the previous local wpoint value is discarded automagically and not joined/widened, providing limited restarting of local wpoints. (See eval for more complete restarting.) *) let wp = HM.mem wpoint x in let l = HM.create 10 in - let prev_dep_vals_x = HM.find_default prev_dep_vals x (HM.create 0) in (* used by abort_verify *) - let eval' = - if tracing then trace "sol2" "eval' %a abortable=%b destab_dep=%b\n" S.Var.pretty_trace x abortable (HM.mem destab_dep x); - if abort && abortable && HM.mem destab_dep x then ( - let unasked_dep_x = ref (HM.find destab_dep x) in - if tracing then trace "sol2" "eval' %a dep=%a\n" S.Var.pretty_trace x vs_pretty !unasked_dep_x; - let all_dep_x_unchanged = ref true in - let all_dep_x_unchanged_verify = ref true in - fun y -> - let (d, changed) = eval l x y in - if tracing then trace "sol2" "eval' %a asked %a changed=%b mem=%b\n" S.Var.pretty_trace x S.Var.pretty_trace y changed (VS.mem y !unasked_dep_x); - if abort_verify then ( - let prev_d = HM.find_default prev_dep_vals_x y (S.Dom.bot ()) in - if not (S.Dom.equal prev_d d) then ( - (* TODO: this is not a bug? change might be covered by destab_front *) - (* if not changed then ( - ignore (Pretty.eprintf "not changed did change: eval %a %a: \nold=%a\n new=%a\n" S.Var.pretty_trace x S.Var.pretty_trace y S.Dom.pretty prev_d S.Dom.pretty d) - ); *) - all_dep_x_unchanged_verify := false; - if tracing then trace "sol2" "eval' %a asked %a abort %B verify\n prev=%a\n now=%a\n" S.Var.pretty_trace x S.Var.pretty_trace y (HM.mem prev_dep_vals_x y) S.Dom.pretty prev_d S.Dom.pretty d; - ) - ); - if VS.mem y !unasked_dep_x then ( - unasked_dep_x := VS.remove y !unasked_dep_x; - if changed then - all_dep_x_unchanged := false; - if tracing then trace "sol2" "eval' %a asked %a checking abort unasked=%a all_unchanged=%b front=%b\n" S.Var.pretty_trace x S.Var.pretty_trace y vs_pretty !unasked_dep_x !all_dep_x_unchanged (HM.mem destab_front x); - let should_abort = VS.is_empty !unasked_dep_x && !all_dep_x_unchanged && not (HM.mem destab_front x) in (* must check front here, because each eval might change it for x *) - let should_abort_verify = !all_dep_x_unchanged_verify in - if should_abort then ( - if abort_verify && not should_abort_verify then ( - failwith (Pretty.sprint ~width:max_int (Pretty.dprintf "TD3 abort verify: should not abort %a" S.Var.pretty_trace x)); - ); - raise AbortEq - ) - ); - d - ) - else - fun y -> - let (d, changed) = eval l x y in - d - in - let (tmp, aborted) = + let tmp = match reuse_eq with | Some d when narrow_reuse && not narrow_reuse_verify -> (* Do not reset deps for reuse of eq *) if tracing then trace "sol2" "eq reused %a\n" S.Var.pretty_trace x; incr Goblintutil.narrow_reuses; - (d, false) + d | _ -> (* The RHS is re-evaluated, all deps are re-trigerred *) HM.replace dep x VS.empty; - try - if abort && abort_verify then ( - (* collect dep vals for x *) - let new_dep_vals_x = HM.create (HM.length prev_dep_vals_x) in - let eval' y = - let d = eval' y in - HM.replace new_dep_vals_x y d; - d - in - let tmp = eq x eval' (side ~x) in - HM.replace prev_dep_vals x new_dep_vals_x; - (tmp, false) - ) - else - (eq x eval' (side ~x), false) - with AbortEq -> - abort_rhs_event x; - if tracing then trace "sol2" "eq aborted %a\n" S.Var.pretty_trace x; - HM.remove destab_dep x; (* TODO: safe to remove here? doesn't prevent some aborts? *) - (* prev_dep_vals remain the same *) - (HM.find rho x, true) (* old *) + eq x (eval l x) (side ~x) in begin match reuse_eq with | Some reuse_eq when narrow_reuse_verify && not (S.Dom.equal tmp reuse_eq) -> @@ -309,7 +223,6 @@ module WP = if tracing then trace "sol" "Var: %a\n" S.Var.pretty_trace x ; if tracing then trace "sol" "Contrib:%a\n" S.Dom.pretty tmp; HM.remove called x; - HM.remove called_changed x; let old = HM.find rho x in (* find old value after eq since wpoint restarting in eq/eval might have changed it meanwhile *) let tmp = if not wp then tmp @@ -327,90 +240,48 @@ module WP = if tracing then trace "sol" "Changed\n"; update_var_event x old tmp; HM.replace rho x tmp; - HM.replace called_changed x (); - if abort then ( - if HM.mem destab_front x then ( - if HM.mem stable x then ( - (* If some side during eq made x unstable, then it should remain in destab_front. - Otherwise recursive solve might prematurely abort it. *) - if tracing then trace "sol2" "front remove %a\n" S.Var.pretty_trace x; - HM.remove destab_front x; - ); - if HM.mem destab_infl x then ( - VS.iter (fun y -> - if tracing then trace "sol2" "pushing front from %a to %a\n" S.Var.pretty_trace x S.Var.pretty_trace y; - if tracing then trace "sol2" "front add %a\n" S.Var.pretty_trace y; - HM.replace destab_front y () - ) (HM.find destab_infl x) - ); - HM.remove destab_infl x - ) - ); destabilize x; - (solve[@tailcall]) x phase true + (solve[@tailcall]) x phase ) else ( (* TODO: why non-equal and non-stable checks in switched order compared to TD3 paper? *) if not (HM.mem stable x) then ( - (* If some side during eq made x unstable, then it should remain in destab_front. - Otherwise recursive solve might prematurely abort it. *) if tracing then trace "sol2" "solve still unstable %a\n" S.Var.pretty_trace x; - (solve[@tailcall]) x Widen changed + (solve[@tailcall]) x Widen ) else ( - if abort && HM.mem destab_front x then ( - if tracing then trace "sol2" "front remove %a\n" S.Var.pretty_trace x; - HM.remove destab_front x; - if tracing then trace "sol2" "not pushing front from %a\n" S.Var.pretty_trace x; - (* don't push front here *) - HM.remove destab_infl x - ); if term && phase = Widen && HM.mem wpoint x then ( (* TODO: or use wp? *) if tracing then trace "sol2" "solve switching to narrow %a\n" S.Var.pretty_trace x; if tracing then trace "sol2" "stable remove %a\n" S.Var.pretty_trace x; HM.remove stable x; HM.remove superstable x; - let reuse_eq = if not aborted then - Some new_eq - else - None (* TODO: for some reason cannot reuse aborted rhs, see 34-localwn_restart/02-hybrid *) - in - (solve[@tailcall]) ?reuse_eq ~abortable:false x Narrow changed + (solve[@tailcall]) ~reuse_eq:new_eq x Narrow ) else if not space && (not term || phase = Narrow) then ( (* this makes e.g. nested loops precise, ex. tests/regression/34-localization/01-nested.c - if we do not remove wpoint, the inner loop head will stay a wpoint and widen the outer loop variable. *) if tracing then trace "sol2" "solve removing wpoint %a (%b)\n" S.Var.pretty_trace x (HM.mem wpoint x); - HM.remove wpoint x; - changed + HM.remove wpoint x ) - else - changed ) ) ) - else if HM.mem called x then - changed || HM.mem called_changed x - else - changed and eq x get set = if tracing then trace "sol2" "eq %a\n" S.Var.pretty_trace x; eval_rhs_event x; match S.system x with | None -> S.Dom.bot () | Some f -> f get set - and simple_solve l x y: S.d * bool = + and simple_solve l x y = if tracing then trace "sol2" "simple_solve %a (rhs: %b)\n" S.Var.pretty_trace y (S.system y <> None); - if S.system y = None then (init y; HM.replace stable y (); (HM.find rho y, true (* TODO: ??? *))) else - if HM.mem rho y || not space then (let changed = solve y Widen false in (HM.find rho y, changed)) else - if abort then failwith "space abort unimplemented" else - if HM.mem called y then (init y; HM.remove l y; (HM.find rho y, true (* TODO: ??? *))) else + if S.system y = None then (init y; HM.replace stable y (); HM.find rho y) else + if HM.mem rho y || not space then (solve y Widen; HM.find rho y) else + if HM.mem called y then (init y; HM.remove l y; HM.find rho y) else (* if HM.mem called y then (init y; let y' = HM.find_default l y (S.Dom.bot ()) in HM.replace rho y y'; HM.remove l y; y') else *) - if cache && HM.mem l y then (HM.find l y, true (* TODO: ??? *)) + if cache && HM.mem l y then HM.find l y else ( HM.replace called y (); - (* TODO: abort? *) - let tmp = eq y (fun z -> fst (eval l x z)) (side ~x) in + let tmp = eq y (eval l x) (side ~x) in HM.remove called y; - if HM.mem rho y then (HM.remove l y; ignore (solve y Widen false); (HM.find rho y, true (* TODO: ??? *))) - else (if cache then HM.replace l y tmp; (tmp, true (* TODO: ??? *))) + if HM.mem rho y then (HM.remove l y; solve y Widen; HM.find rho y) + else (if cache then HM.replace l y tmp; tmp) ) - and eval l x y: S.d * bool = + and eval l x y = if tracing then trace "sol2" "eval %a ## %a\n" S.Var.pretty_trace x S.Var.pretty_trace y; get_var_event y; if HM.mem called y then ( @@ -421,11 +292,6 @@ module WP = if not (restart_once && HM.mem restarted_wpoint y) then ( if tracing then trace "sol2" "wpoint restart %a ## %a\n" S.Var.pretty_trace y S.Dom.pretty (HM.find_default rho y (S.Dom.bot ())); HM.replace rho y (S.Dom.bot ()); - HM.replace called_changed y (); (* just in case *) - (* required for abort (front), for 34-localwn_restart/21-restart_abort_aget *) - HM.remove stable y; - HM.remove superstable y; - destabilize y; if restart_once then (* avoid populating hashtable unnecessarily *) HM.replace restarted_wpoint y (); ) @@ -434,7 +300,7 @@ module WP = ); let tmp = simple_solve l x y in if HM.mem rho y then add_infl y x; - if tracing then trace "sol2" "eval %a ## %a -> %a\n" S.Var.pretty_trace x S.Var.pretty_trace y S.Dom.pretty (fst tmp); + if tracing then trace "sol2" "eval %a ## %a -> %a\n" S.Var.pretty_trace x S.Var.pretty_trace y S.Dom.pretty tmp; tmp and side ?x y d = (* side from x to y; only to variables y w/o rhs; x only used for trace *) if tracing then trace "sol2" "side to %a (wpx: %b) from %a ## value: %a\n" S.Var.pretty_trace y (HM.mem wpoint y) (Pretty.docOpt (S.Var.pretty_trace ())) x S.Dom.pretty d; @@ -512,40 +378,15 @@ module WP = (* solve x Widen *) in - let destabilize_front ~front x w = - if abort then ( - if front then ( - VS.iter (fun y -> - if tracing then trace "sol2" "front add %a (infl)\n" S.Var.pretty_trace y; - HM.replace destab_front y () - ) w; - (* Also add front via destab_infl in case infl has already been removed by previous destabilize. - This fixes 29-svcomp/27-td3-front-via-destab-infl. *) - VS.iter (fun y -> - if tracing then trace "sol2" "front add %a (destab_infl)\n" S.Var.pretty_trace y; - HM.replace destab_front y () - ) (HM.find_default destab_infl x VS.empty) - ) - else ( - HM.replace destab_infl x (VS.union w (HM.find_default destab_infl x VS.empty)); - VS.iter (fun y -> - HM.replace destab_dep y (VS.add x (try HM.find destab_dep y with Not_found -> VS.empty)) - ) w - ) - ) - in - - let rec destabilize_normal ?(front=true) x = + let rec destabilize_normal x = if tracing then trace "sol2" "destabilize %a\n" S.Var.pretty_trace x; - trace_called (); let w = HM.find_default infl x VS.empty in HM.replace infl x VS.empty; - destabilize_front ~front x w; VS.iter (fun y -> if tracing then trace "sol2" "stable remove %a\n" S.Var.pretty_trace y; HM.remove stable y; HM.remove superstable y; - if not (HM.mem called y) then destabilize_normal ~front:false y + if not (HM.mem called y) then destabilize_normal y ) w in @@ -575,7 +416,7 @@ module WP = in (* destabilize which restarts side-effected vars *) - let rec destabilize_with_side ?(front=true) x = + let rec destabilize_with_side x = if tracing then trace "sol2" "destabilize_with_side %a\n" S.Var.pretty_trace x; (* is side-effected var (global/function entry)? *) @@ -593,9 +434,6 @@ module WP = (* restart side-effected var *) restart_leaf x; - (* add side_dep to front to prevent them from being aborted *) - destabilize_front ~front:true x w; - (* destabilize side dep to redo side effects *) VS.iter (fun y -> if tracing then trace "sol2" "destabilize_with_side %a side_dep %a\n" S.Var.pretty_trace x S.Var.pretty_trace y; @@ -603,22 +441,21 @@ module WP = HM.remove stable y; HM.remove superstable y; if restart_destab_with_sides then - destabilize_with_side ~front:false y + destabilize_with_side y else - destabilize_normal ~front:false y + destabilize_normal y ) w ); (* destabilize eval infl *) let w = HM.find_default infl x VS.empty in HM.replace infl x VS.empty; - destabilize_front ~front x w; VS.iter (fun y -> if tracing then trace "sol2" "destabilize_with_side %a infl %a\n" S.Var.pretty_trace x S.Var.pretty_trace y; if tracing then trace "sol2" "stable remove %a\n" S.Var.pretty_trace y; HM.remove stable y; HM.remove superstable y; - destabilize_with_side ~front:false y + destabilize_with_side y ) w; (* destabilize side infl *) @@ -630,7 +467,7 @@ module WP = if tracing then trace "sol2" "stable remove %a\n" S.Var.pretty_trace y; HM.remove stable y; HM.remove superstable y; - destabilize_with_side ~front:false y + destabilize_with_side y ) w in @@ -784,8 +621,6 @@ module WP = let w = HM.find_default side_dep x VS.empty in if not (VS.is_empty w) then ( HM.remove side_dep x; - (* add side_dep to front to prevent them from being aborted *) - destabilize_front ~front:true x w; (* destabilize side dep to redo side effects *) VS.iter (fun y -> if tracing then trace "sol2" "destabilize_leaf %a side_dep %a\n" S.Var.pretty_trace x S.Var.pretty_trace y; @@ -870,7 +705,7 @@ module WP = let op = if GobConfig.get_string "incremental.reluctant.compare" = "leq" then S.Dom.leq else S.Dom.equal in HM.iter (fun x (old_rho, old_infl) -> ignore @@ Pretty.printf "test for %a\n" Node.pretty_trace (S.Var.node x); - ignore (solve x Widen false); (* TODO: use returned changed for comparison? *) + solve x Widen; if not (op (HM.find rho x) old_rho) then ( print_endline "Destabilization required..."; HM.replace infl x old_infl; @@ -905,7 +740,7 @@ module WP = print_newline (); flush_all (); ); - List.iter (fun x -> ignore (solve x Widen false)) unstable_vs; + List.iter (fun x -> solve x Widen) unstable_vs; solver (); ) in diff --git a/src/util/goblintutil.ml b/src/util/goblintutil.ml index 5ab8a42223..0f4ef904fc 100644 --- a/src/util/goblintutil.ml +++ b/src/util/goblintutil.ml @@ -101,7 +101,6 @@ let seconds_of_duration_string = let vars = ref 0 let evals = ref 0 let narrow_reuses = ref 0 -let aborts = ref 0 (* print GC statistics; taken from Cil.Stats.print which also includes timing; there's also Gc.print_stat, but it's in words instead of MB and more info than we want (also slower than quick_stat since it goes through the heap) *) let print_gc_quick_stat chn = diff --git a/src/util/options.schema.json b/src/util/options.schema.json index 987d8f32a3..386b639b4f 100644 --- a/src/util/options.schema.json +++ b/src/util/options.schema.json @@ -1911,18 +1911,6 @@ }, "additionalProperties": false }, - "abort": { - "title": "solvers.td3.abort", - "description": "TODO", - "type": "boolean", - "default": false - }, - "abort-verify": { - "title": "solvers.td3.abort-verify", - "description": "TODO", - "type": "boolean", - "default": false - }, "verify": { "title": "solvers.td3.verify", "description": "Check TD3 data structure invariants", diff --git a/tests/incremental/11-restart/48-local-wpoint-funcall.json b/tests/incremental/11-restart/48-local-wpoint-funcall.json index d5cb77d8e7..2f428497b1 100644 --- a/tests/incremental/11-restart/48-local-wpoint-funcall.json +++ b/tests/incremental/11-restart/48-local-wpoint-funcall.json @@ -11,9 +11,7 @@ "enabled": true, "once": true } - }, - "abort": false, - "abort-verify": false + } } } } \ No newline at end of file diff --git a/tests/incremental/12-abort/01-abort_aget.c b/tests/incremental/12-abort/01-abort_aget.c deleted file mode 100644 index 2520756134..0000000000 --- a/tests/incremental/12-abort/01-abort_aget.c +++ /dev/null @@ -1,13 +0,0 @@ -int a; -void b(); - -void c() {} - -int d() { - return 0; -} - -main() { - b(d); - c(); -} \ No newline at end of file diff --git a/tests/incremental/12-abort/01-abort_aget.json b/tests/incremental/12-abort/01-abort_aget.json deleted file mode 100644 index 1a7c6954fe..0000000000 --- a/tests/incremental/12-abort/01-abort_aget.json +++ /dev/null @@ -1,44 +0,0 @@ -{ - "ana": { - "int": { - "interval": true - } - }, - "sem": { - "int": { - "signed_overflow": "assume_none" - }, - "unknown_function": { - "invalidate": { - "globals": false - } - } - }, - "dbg": { - "debug": false - }, - "solvers": { - "td3": { - "restart": { - "wpoint": { - "enabled": false, - "once": true - } - }, - "abort": true, - "abort-verify": false - } - }, - "incremental": { - "reluctant": { - "on": false, - "compare": "equal" - }, - "restart": { - "sided": { - "enabled": true, - "only-global": false - } - } - } -} diff --git a/tests/incremental/12-abort/01-abort_aget.patch b/tests/incremental/12-abort/01-abort_aget.patch deleted file mode 100644 index ac5c9f4c6b..0000000000 --- a/tests/incremental/12-abort/01-abort_aget.patch +++ /dev/null @@ -1,11 +0,0 @@ ---- tests/incremental/12-abort/01-abort_aget.c -+++ tests/incremental/12-abort/01-abort_aget.c -@@ -4,7 +4,7 @@ void b(); - void c() {} - - int d() { -- return 0; -+ return 1; - } - - main() { diff --git a/tests/incremental/12-abort/02-abort-smtprc.c b/tests/incremental/12-abort/02-abort-smtprc.c deleted file mode 100644 index 8c1eee4275..0000000000 --- a/tests/incremental/12-abort/02-abort-smtprc.c +++ /dev/null @@ -1,36 +0,0 @@ -struct { - unsigned a; -} b; -int c; -void d(); -void f(); -void h(); -int i(); -void main() { - int e; - if (e) - b.a++; - h(); -} -void j() { - int g = 0; - i(&g); -} -void h() { - if (b.a) - d(j); -} -void k() {} -int i(int l) { - int m; - while (m) { - f(l); - if (c) - return (-1); - d(l); - } -} -void f() { - d(b); - k(); -} \ No newline at end of file diff --git a/tests/incremental/12-abort/02-abort-smtprc.json b/tests/incremental/12-abort/02-abort-smtprc.json deleted file mode 100644 index 1a7c6954fe..0000000000 --- a/tests/incremental/12-abort/02-abort-smtprc.json +++ /dev/null @@ -1,44 +0,0 @@ -{ - "ana": { - "int": { - "interval": true - } - }, - "sem": { - "int": { - "signed_overflow": "assume_none" - }, - "unknown_function": { - "invalidate": { - "globals": false - } - } - }, - "dbg": { - "debug": false - }, - "solvers": { - "td3": { - "restart": { - "wpoint": { - "enabled": false, - "once": true - } - }, - "abort": true, - "abort-verify": false - } - }, - "incremental": { - "reluctant": { - "on": false, - "compare": "equal" - }, - "restart": { - "sided": { - "enabled": true, - "only-global": false - } - } - } -} diff --git a/tests/incremental/12-abort/02-abort-smtprc.patch b/tests/incremental/12-abort/02-abort-smtprc.patch deleted file mode 100644 index 74a2e64e2d..0000000000 --- a/tests/incremental/12-abort/02-abort-smtprc.patch +++ /dev/null @@ -1,11 +0,0 @@ ---- tests/incremental/12-abort/02-abort-smtprc.c -+++ tests/incremental/12-abort/02-abort-smtprc.c -@@ -26,7 +26,7 @@ int i(int l) { - while (m) { - f(l); - if (c) -- return (-1); -+ return (-2); - d(l); - } - } diff --git a/tests/regression/04-mutex/80-td3-self-abort.c b/tests/regression/04-mutex/80-td3-self-abort.c deleted file mode 100644 index 50a2ece39d..0000000000 --- a/tests/regression/04-mutex/80-td3-self-abort.c +++ /dev/null @@ -1,15 +0,0 @@ -#include - -int myglobal; - -void *t_fun(void *arg) { - myglobal=1; // RACE! - return NULL; -} - -int main(void) { - pthread_t id; - pthread_create(&id, NULL, t_fun, NULL); - myglobal = myglobal+1; // RACE! - return 0; -} diff --git a/tests/regression/29-svcomp/27-td3-front-via-destab-infl.c b/tests/regression/29-svcomp/27-td3-front-via-destab-infl.c deleted file mode 100644 index a0e5b8a00e..0000000000 --- a/tests/regression/29-svcomp/27-td3-front-via-destab-infl.c +++ /dev/null @@ -1,42 +0,0 @@ -// NOMARSHAL PARAM: --set ana.activated[+] var_eq --set ana.activated[+] symb_locks --set ana.activated[+] region --enable ana.sv-comp.enabled --set ana.specification "CHECK( init(main()), LTL(G ! call(reach_error())) )" - -// creduced from ldv-linux-4.2-rc1/linux-4.2-rc1.tar.xz-43_2a-drivers--scsi--qla4xxx--qla4xxx.ko-entry_point.cil.out.i -// this program and params are really minimal, which produced a TD3 abort verify error, so don't simplify - -int a; - -void c(); - -void b() { - c(); -} - -unsigned e() { - int d; - if (d) - c(); - return; -} - -void c() { - int f; - unsigned g = 0; - - do { - g = e(); - if (a) - return; - - do { - f++; - } while (f); - - } while (g); - - b(); -} - -int main() { - b(); - return 0; -} diff --git a/tests/regression/34-localwn_restart/21-restart_abort_aget.c b/tests/regression/34-localwn_restart/21-restart_abort_aget.c deleted file mode 100644 index 58e62e6f87..0000000000 --- a/tests/regression/34-localwn_restart/21-restart_abort_aget.c +++ /dev/null @@ -1,23 +0,0 @@ -// PARAM: --enable solvers.td3.restart.wpoint.enabled --enable solvers.td3.abort - -#include -struct a { - int b; -} c(), *f; - -int g; -void d(); -void e(); - -int main() { - void *h = calloc(1, sizeof(struct a)); - f = h; - d(e); - while (1) { - g = c; - if (c) - break; - f->b = 0; - } - d(h); -} \ No newline at end of file diff --git a/tests/regression/46-apron2/01-td3-self-abort-complex.c b/tests/regression/46-apron2/01-td3-self-abort-complex.c deleted file mode 100644 index d53beb6012..0000000000 --- a/tests/regression/46-apron2/01-td3-self-abort-complex.c +++ /dev/null @@ -1,30 +0,0 @@ -// SKIP PARAM: --set ana.activated[+] apron -#include -#include - -int g = 1; -int h = 1; -pthread_mutex_t A = PTHREAD_MUTEX_INITIALIZER; - -void *t_fun(void *arg) { - int x, y; // rand - pthread_mutex_lock(&A); - g = x; - h = x; - pthread_mutex_unlock(&A); - pthread_mutex_lock(&A); - pthread_mutex_unlock(&A); - pthread_mutex_lock(&A); - if (y) - g = x; - assert(g == h); // UNKNOWN? - pthread_mutex_unlock(&A); - return NULL; -} - -int main(void) { - pthread_t id; - pthread_create(&id, NULL, t_fun, NULL); - - return 0; -} From 93069914a964fc05c151276b10e8b049e70ee7bb Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Fri, 13 May 2022 17:08:51 +0300 Subject: [PATCH 372/402] Use deriving show for TD3 phase --- src/solvers/td3.ml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/solvers/td3.ml b/src/solvers/td3.ml index b45d8cd04a..8f21ee3954 100644 --- a/src/solvers/td3.ml +++ b/src/solvers/td3.ml @@ -80,7 +80,7 @@ module WP = module HPM = Hashtbl.Make (P) - type phase = Widen | Narrow + type phase = Widen | Narrow [@@deriving show] let current_var = ref None @@ -185,7 +185,7 @@ module WP = HM.mem called y || destabilize_vs y || b || was_stable && List.mem y vs ) w false and solve ?reuse_eq x phase = - if tracing then trace "sol2" "solve %a, phase: %s, called: %b, stable: %b\n" S.Var.pretty_trace x (match phase with Widen -> "Widen" | Narrow -> "Narrow") (HM.mem called x) (HM.mem stable x); + if tracing then trace "sol2" "solve %a, phase: %s, called: %b, stable: %b\n" S.Var.pretty_trace x (show_phase phase) (HM.mem called x) (HM.mem stable x); init x; assert (S.system x <> None); if not (HM.mem called x || HM.mem stable x) then ( From 60168357f464e13ef0d11217215049164cbe2aff Mon Sep 17 00:00:00 2001 From: Michael Schwarz Date: Fri, 13 May 2022 17:34:50 +0200 Subject: [PATCH 373/402] Add example where `__goblint_assume_join` causes unneccessary precision loss --- .../46-apron2/04-other-assume-inprec.c | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 tests/regression/46-apron2/04-other-assume-inprec.c diff --git a/tests/regression/46-apron2/04-other-assume-inprec.c b/tests/regression/46-apron2/04-other-assume-inprec.c new file mode 100644 index 0000000000..b07c5b42f1 --- /dev/null +++ b/tests/regression/46-apron2/04-other-assume-inprec.c @@ -0,0 +1,30 @@ +// SKIP PARAM: --set ana.activated[+] apron --set ana.path_sens[+] threadflag --set ana.activated[+] threadJoins --sets ana.apron.privatization mutex-meet-tid +#include +#include + +int g = 10; +int h = 10; +pthread_mutex_t A = PTHREAD_MUTEX_INITIALIZER; + +void *t_fun(void *arg) { + g = 7; + return NULL; +} + +int main(void) { + int t; + + pthread_t id; + pthread_create(&id, NULL, t_fun, NULL); + pthread_join(id,NULL); + + g = h; + assert(g == h); + + // __goblint_assume_join for something Goblint knows is joined should not worsen precision + __goblint_assume_join(id); + + assert(g == h); + + return 0; +} From 22d6da850252ca8f422452e4626b727d4fdb5a16 Mon Sep 17 00:00:00 2001 From: Michael Schwarz Date: Fri, 13 May 2022 17:40:51 +0200 Subject: [PATCH 374/402] Add problematic index access --- .../06-symbeq/39-funloop_index_bad.c | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 tests/regression/06-symbeq/39-funloop_index_bad.c diff --git a/tests/regression/06-symbeq/39-funloop_index_bad.c b/tests/regression/06-symbeq/39-funloop_index_bad.c new file mode 100644 index 0000000000..7bd0bb78ea --- /dev/null +++ b/tests/regression/06-symbeq/39-funloop_index_bad.c @@ -0,0 +1,36 @@ +// PARAM: --disable ana.mutex.disjoint_types --set ana.activated[+] "'var_eq'" --set ana.activated[+] "'symb_locks'" +// copy of 06/02 with additional index accesses (that are wrong) +#include +#include + +struct cache_entry { + int refs; + pthread_mutex_t refs_mutex; +} cache[10]; + +void cache_entry_addref(struct cache_entry *entry) { + pthread_mutex_lock(&entry->refs_mutex); + entry->refs++; // NORACE + (*entry).refs++; // NORACE + entry[1].refs++; // RACE + pthread_mutex_unlock(&entry->refs_mutex); +} + +void *t_fun(void *arg) { + int i; + for(i=0; i<9; i++) + cache_entry_addref(&cache[i]); // NORACE + return NULL; +} + +int main () { + for (int i = 0; i < 10; i++) + pthread_mutex_init(&cache[i].refs_mutex, NULL); + + int i; + pthread_t t1; + pthread_create(&t1, NULL, t_fun, NULL); + for(i=0; i<9; i++) + cache_entry_addref(&cache[i]); // NORACE + return 0; +} From a482bd1c266490441a080ddd8fd88605b3ca6355 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Mon, 16 May 2022 12:20:19 +0300 Subject: [PATCH 375/402] Fix Apron mutex-meet-tid imprecision by force joining must-joined threads --- src/analyses/apron/apronPriv.apron.ml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/analyses/apron/apronPriv.apron.ml b/src/analyses/apron/apronPriv.apron.ml index 1b8a71f4c4..0959828fe1 100644 --- a/src/analyses/apron/apronPriv.apron.ml +++ b/src/analyses/apron/apronPriv.apron.ml @@ -991,10 +991,11 @@ struct st (* don't consider anything more joined, matches threadJoins analysis *) else ( (* fold throws if the thread set is top *) + let tids' = ConcDomain.ThreadSet.diff tids (ask.f Q.MustJoinedThreads) in (* avoid unnecessary imprecision by force joining already must-joined threas, e.g. 46-apron2/04-other-assume-inprec *) let (lmust', l') = ConcDomain.ThreadSet.fold (fun tid (lmust, l) -> let lmust',l' = G.thread (getg (V.thread tid)) in (LMust.union lmust' lmust, L.join l l') - ) tids (lmust, l) + ) tids' (lmust, l) in {st with priv = (w, lmust', l')} ) From 67211c2c0eb7c2b61efa5b9db82976fecaf7ed77 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Mon, 16 May 2022 13:01:08 +0300 Subject: [PATCH 376/402] Fix annotations in 06-symbeq/39-funloop_index_bad --- tests/regression/06-symbeq/39-funloop_index_bad.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/regression/06-symbeq/39-funloop_index_bad.c b/tests/regression/06-symbeq/39-funloop_index_bad.c index 7bd0bb78ea..1983887796 100644 --- a/tests/regression/06-symbeq/39-funloop_index_bad.c +++ b/tests/regression/06-symbeq/39-funloop_index_bad.c @@ -10,9 +10,9 @@ struct cache_entry { void cache_entry_addref(struct cache_entry *entry) { pthread_mutex_lock(&entry->refs_mutex); - entry->refs++; // NORACE - (*entry).refs++; // NORACE - entry[1].refs++; // RACE + entry->refs++; // RACE! + (*entry).refs++; // RACE! + entry[1].refs++; // RACE! pthread_mutex_unlock(&entry->refs_mutex); } From 92c7ea46264bee2eda7ceb621310affb7a2ed0ac Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Mon, 16 May 2022 15:41:11 +0300 Subject: [PATCH 377/402] Replace symb_locks and var_eq IndexPI handling with very ad-hoc one This fixes the soundness, but still works for chrony story. --- src/analyses/varEq.ml | 12 ++++++++++-- src/cdomains/exp.ml | 6 ++---- tests/regression/06-symbeq/37-funloop_index.c | 6 +++--- 3 files changed, 15 insertions(+), 9 deletions(-) diff --git a/src/analyses/varEq.ml b/src/analyses/varEq.ml index 9ff73d090e..dfde1a3de8 100644 --- a/src/analyses/varEq.ml +++ b/src/analyses/varEq.ml @@ -530,8 +530,16 @@ struct let rec eq_set_clos e s = if M.tracing then M.traceli "var_eq" "eq_set_clos %a\n" d_plainexp e; let r = match e with - | BinOp ((PlusPI | IndexPI), e1, e2, _) -> - eq_set_clos e1 s (* TODO: what about e2? add to some Index offset to all? *) + | AddrOf (Mem (BinOp (IndexPI, a, i, _)), os) -> + (* convert IndexPI to Index offset *) + (* TODO: this applies eq_set_clos under the offset, unlike cases below; should generalize? *) + Queries.ES.fold (fun e acc -> (* filter_map *) + match e with + | CastE (_, StartOf a') -> (* eq_set adds casts *) + let e' = AddrOf (Cil.addOffsetLval (Index (i, os)) a') in (* TODO: re-add cast? *) + Queries.ES.add e' acc + | _ -> acc + ) (eq_set_clos a s) (Queries.ES.empty ()) | SizeOf _ | SizeOfE _ | SizeOfStr _ diff --git a/src/cdomains/exp.ml b/src/cdomains/exp.ml index 3e382642bd..d02a90a6b8 100644 --- a/src/cdomains/exp.ml +++ b/src/cdomains/exp.ml @@ -12,8 +12,7 @@ struct (* TODO: what does interesting mean? *) let rec interesting x = match x with - | BinOp ((PlusPI | IndexPI), e1, e2, _) -> - interesting e1 (* TODO: what about e2? *) + (* TODO: handle IndexPI like var_eq eq_set_clos? *) | SizeOf _ | SizeOfE _ | SizeOfStr _ @@ -294,8 +293,7 @@ struct in let rec helper exp = match exp with - | BinOp ((PlusPI | IndexPI), e1, e2, _) -> - helper e1 (* TODO: what about e2? add to some Index offset to all? *) + (* TODO: handle IndexPI like var_eq eq_set_clos? *) | SizeOf _ | SizeOfE _ | SizeOfStr _ diff --git a/tests/regression/06-symbeq/37-funloop_index.c b/tests/regression/06-symbeq/37-funloop_index.c index 831ad62769..d4c269cc05 100644 --- a/tests/regression/06-symbeq/37-funloop_index.c +++ b/tests/regression/06-symbeq/37-funloop_index.c @@ -10,9 +10,9 @@ struct cache_entry { void cache_entry_addref(struct cache_entry *entry) { pthread_mutex_lock(&entry->refs_mutex); - entry->refs++; // NORACE - (*entry).refs++; // NORACE - entry[0].refs++; // NORACE + entry->refs++; // TODO NORACE + (*entry).refs++; // TODO NORACE + entry[0].refs++; // TODO NORACE pthread_mutex_unlock(&entry->refs_mutex); } From 94fd11f57f0b74c5033e40ff42725c525bc4bd33 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Mon, 16 May 2022 17:59:15 +0300 Subject: [PATCH 378/402] Handle IndexPI in Exp.interesting to fix string_fortified.h race in 06-symbeq/38-chrony-name2ipaddress --- src/cdomains/exp.ml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/cdomains/exp.ml b/src/cdomains/exp.ml index d02a90a6b8..8e74a6f417 100644 --- a/src/cdomains/exp.ml +++ b/src/cdomains/exp.ml @@ -12,7 +12,8 @@ struct (* TODO: what does interesting mean? *) let rec interesting x = match x with - (* TODO: handle IndexPI like var_eq eq_set_clos? *) + | AddrOf (Mem (BinOp (IndexPI, a, _i, _)), _os) -> + interesting a | SizeOf _ | SizeOfE _ | SizeOfStr _ From 3ec784c8534a3ec3263bf011cf6b8538e060eb45 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Tue, 17 May 2022 16:42:01 +0300 Subject: [PATCH 379/402] Extract CurrentVarEqConstrSys from TD3 --- src/framework/constraints.ml | 26 ++++++++++++++++++++++++++ src/solvers/td3.ml | 25 +++---------------------- 2 files changed, 29 insertions(+), 22 deletions(-) diff --git a/src/framework/constraints.ml b/src/framework/constraints.ml index f851afe7bb..78f2b8401a 100644 --- a/src/framework/constraints.ml +++ b/src/framework/constraints.ml @@ -1412,3 +1412,29 @@ struct ignore (Pretty.printf "Nodes comparison summary: %t\n" (fun () -> msg)); print_newline (); end + +(** [EqConstrSys] where [current_var] indicates the variable whose right-hand side is currently being evaluated. *) +module CurrentVarEqConstrSys (S: EqConstrSys) = +struct + let current_var = ref None + + module S = + struct + include S + + let system x = + match S.system x with + | None -> None + | Some f -> + let f' get set = + let old_current_var = !current_var in + current_var := Some x; + Fun.protect ~finally:(fun () -> + current_var := old_current_var + ) (fun () -> + f get set + ) + in + Some f' + end +end diff --git a/src/solvers/td3.ml b/src/solvers/td3.ml index 8f21ee3954..f154324e5e 100644 --- a/src/solvers/td3.ml +++ b/src/solvers/td3.ml @@ -82,27 +82,8 @@ module WP = type phase = Widen | Narrow [@@deriving show] - let current_var = ref None - - module S = - struct - include S - - let system x = - match S.system x with - | None -> None - | Some f -> - let f' get set = - let old_current_var = !current_var in - current_var := Some x; - Fun.protect ~finally:(fun () -> - current_var := old_current_var - ) (fun () -> - f get set - ) - in - Some f' - end + module CurrentVarS = Constraints.CurrentVarEqConstrSys (S) + module S = CurrentVarS.S let solve box st vs data = let term = GobConfig.get_bool "solvers.td3.term" in @@ -919,7 +900,7 @@ module WP = (* hook to collect new messages *) Messages.Table.add_hook := (fun m -> - match !current_var with + match !CurrentVarS.current_var with | Some x -> HM.add var_messages x m | None -> () ) From 8c9777c69943ed7f6e95b783528e609d05b5cf48 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Tue, 17 May 2022 16:57:05 +0300 Subject: [PATCH 380/402] Document incremental TD3 data structures --- src/solvers/td3.ml | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/solvers/td3.ml b/src/solvers/td3.ml index f154324e5e..e21a11dad5 100644 --- a/src/solvers/td3.ml +++ b/src/solvers/td3.ml @@ -33,9 +33,9 @@ module WP = mutable stable: unit HM.t; mutable side_dep: VS.t HM.t; (** Dependencies of side-effected variables. Knowing these allows restarting them and re-triggering all side effects. *) mutable side_infl: VS.t HM.t; (** Influences to side-effected variables. Not normally in [infl], but used for restarting them. *) - mutable var_messages: Message.t HM.t; - mutable rho_write: S.Dom.t HM.t HM.t; - mutable dep: VS.t HM.t + mutable var_messages: Message.t HM.t; (** Messages from right-hand sides of variables. Used for incremental postsolving. *) + mutable rho_write: S.Dom.t HM.t HM.t; (** Side effects from variables to write-only variables with values. Used for fast incremental restarting of write-only variables. *) + mutable dep: VS.t HM.t; (** Dependencies of variables. Inverse of [infl]. Used for fast pre-reachable pruning in incremental postsolving. *) } type marshal = solver_data @@ -128,8 +128,6 @@ module WP = let var_messages = data.var_messages in let rho_write = data.rho_write in - - (* Tracks dependencies between an unknown and the things it depends on *) let dep = data.dep in let () = print_solver_stats := fun () -> From b073cce961f0fdd3bd8fdf38df4549b1590ea045 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Tue, 17 May 2022 17:11:38 +0300 Subject: [PATCH 381/402] Add descriptions for new incremental TD3 options --- src/solvers/td3.ml | 8 -------- src/util/options.schema.json | 16 ++++++++-------- 2 files changed, 8 insertions(+), 16 deletions(-) diff --git a/src/solvers/td3.ml b/src/solvers/td3.ml index e21a11dad5..49079d88c0 100644 --- a/src/solvers/td3.ml +++ b/src/solvers/td3.ml @@ -103,20 +103,12 @@ module WP = let side_dep = data.side_dep in let side_infl = data.side_infl in - (* If true, incremental destabilized side-effected vars will be restarted. - If false, they are not. *) let restart_sided = GobConfig.get_bool "incremental.restart.sided.enabled" in - (* If true, incremental side-effected var restart will only restart destabilized globals (using hack). - If false, it will restart all destabilized side-effected vars. *) let restart_only_globals = GobConfig.get_bool "incremental.restart.sided.only-global" in let restart_only_access = GobConfig.get_bool "incremental.restart.sided.only-access" in let restart_destab_with_sides = GobConfig.get_bool "incremental.restart.sided.destab-with-sides" in - (* If true, wpoint will be restarted to bot when added. - This allows incremental to avoid reusing and republishing imprecise local values due to globals (which get restarted). *) let restart_wpoint = GobConfig.get_bool "solvers.td3.restart.wpoint.enabled" in - (* If true, each wpoint will be restarted once when added. - If false, it will be restarted each time it is added again (wpoints are removed after Narrow). *) let restart_once = GobConfig.get_bool "solvers.td3.restart.wpoint.once" in let restarted_wpoint = HM.create 10 in diff --git a/src/util/options.schema.json b/src/util/options.schema.json index 386b639b4f..53bf2aa162 100644 --- a/src/util/options.schema.json +++ b/src/util/options.schema.json @@ -1041,25 +1041,25 @@ "properties": { "enabled": { "title": "incremental.restart.sided.enabled", - "description": "TODO", + "description": "Restart affected side-effected variables (transitively) to bot.", "type": "boolean", "default": false }, "only-global": { "title": "incremental.restart.sided.only-global", - "description": "TODO", + "description": "Restart only constraint system globals.", "type": "boolean", "default": false }, "only-access" : { "title" : "incremental.restart.sided.only-access", - "description" : "TODO", + "description" : "Restart only write-only variables.", "type" : "boolean", "default" : false }, "destab-with-sides": { "title" : "incremental.restart.sided.destab-with-sides", - "description" : "TODO", + "description" : "TODO BROKEN", "type" : "boolean", "default" : true } @@ -1875,13 +1875,13 @@ }, "narrow-reuse": { "title": "solvers.td3.narrow-reuse", - "description": "TODO", + "description": "Reuse value when switching from widening to narrowing phase. Avoids one unnecessary re-evaluation.", "type": "boolean", "default": true }, "narrow-reuse-verify": { "title": "solvers.td3.narrow-reuse-verify", - "description": "TODO", + "description": "Instead of reusing value when switching from widening to narrowing phase, just verify that the reuse would be correct by re-evaluating.", "type": "boolean", "default": false }, @@ -1895,13 +1895,13 @@ "properties": { "enabled": { "title": "solvers.td3.restart.wpoint.enabled", - "description": "TODO", + "description": "Restart wpoint to bot when (re-)detected. Allows incremental to avoid reusing and republishing imprecise local values due to globals (which get restarted).", "type": "boolean", "default": false }, "once": { "title": "solvers.td3.restart.wpoint.once", - "description": "TODO", + "description": "Restart wpoint only on first detection. Useful for incremental loading.", "type": "boolean", "default": false } From 21e75ec6e0a48b66369f1b8fcfbc0d9dcf909abe Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Tue, 17 May 2022 17:15:20 +0300 Subject: [PATCH 382/402] Rename option incremental.reluctant.on -> incremental.reluctant.enabled for consistency --- src/solvers/td3.ml | 2 +- src/util/options.schema.json | 4 ++-- tests/incremental/01-force-reanalyze/00-int.json | 2 +- tests/incremental/01-force-reanalyze/01-int-reluctant.json | 2 +- .../03-precision-annotation/02-reluctant-int-annotation.json | 2 +- .../03-reluctant-int-annotation-dyn.json | 2 +- tests/incremental/11-restart/08-side-restart.json | 2 +- .../13-restart-write/06-mutex-simple-reluctant.json | 2 +- .../13-restart-write/07-mutex-simple-reluctant2.json | 2 +- .../13-restart-write/08-mutex-simple-reluctant3.json | 2 +- 10 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/solvers/td3.ml b/src/solvers/td3.ml index 49079d88c0..3d0bf9d353 100644 --- a/src/solvers/td3.ml +++ b/src/solvers/td3.ml @@ -477,7 +477,7 @@ module WP = ) in - let reluctant = GobConfig.get_bool "incremental.reluctant.on" in + let reluctant = GobConfig.get_bool "incremental.reluctant.enabled" in let reanalyze_entry f = (* destabilize the entry points of a changed function when reluctant is off, or the function is to be force-reanalyzed *) diff --git a/src/util/options.schema.json b/src/util/options.schema.json index 53bf2aa162..07a605ad79 100644 --- a/src/util/options.schema.json +++ b/src/util/options.schema.json @@ -988,8 +988,8 @@ "title": "incremental.reluctant", "type": "object", "properties": { - "on": { - "title": "incremental.reluctant.on", + "enabled": { + "title": "incremental.reluctant.enabled", "description": "Destabilize nodes in changed functions reluctantly", "type": "boolean", diff --git a/tests/incremental/01-force-reanalyze/00-int.json b/tests/incremental/01-force-reanalyze/00-int.json index 5448288b6b..a459e0a7a9 100644 --- a/tests/incremental/01-force-reanalyze/00-int.json +++ b/tests/incremental/01-force-reanalyze/00-int.json @@ -15,7 +15,7 @@ "funs": ["f"] }, "reluctant" : { - "on" : false + "enabled" : false } } } diff --git a/tests/incremental/01-force-reanalyze/01-int-reluctant.json b/tests/incremental/01-force-reanalyze/01-int-reluctant.json index 6fe26c0b7e..006e469abb 100644 --- a/tests/incremental/01-force-reanalyze/01-int-reluctant.json +++ b/tests/incremental/01-force-reanalyze/01-int-reluctant.json @@ -15,7 +15,7 @@ "funs": ["f"] }, "reluctant" : { - "on": true + "enabled": true }, "postsolver": { "enabled": false diff --git a/tests/incremental/03-precision-annotation/02-reluctant-int-annotation.json b/tests/incremental/03-precision-annotation/02-reluctant-int-annotation.json index ff13de39d1..6964e3b4cc 100644 --- a/tests/incremental/03-precision-annotation/02-reluctant-int-annotation.json +++ b/tests/incremental/03-precision-annotation/02-reluctant-int-annotation.json @@ -12,7 +12,7 @@ }, "incremental": { "reluctant": { - "on": true + "enabled": true }, "postsolver": { "enabled": false diff --git a/tests/incremental/03-precision-annotation/03-reluctant-int-annotation-dyn.json b/tests/incremental/03-precision-annotation/03-reluctant-int-annotation-dyn.json index ff13de39d1..6964e3b4cc 100644 --- a/tests/incremental/03-precision-annotation/03-reluctant-int-annotation-dyn.json +++ b/tests/incremental/03-precision-annotation/03-reluctant-int-annotation-dyn.json @@ -12,7 +12,7 @@ }, "incremental": { "reluctant": { - "on": true + "enabled": true }, "postsolver": { "enabled": false diff --git a/tests/incremental/11-restart/08-side-restart.json b/tests/incremental/11-restart/08-side-restart.json index 6fbedae790..e87f2900a0 100644 --- a/tests/incremental/11-restart/08-side-restart.json +++ b/tests/incremental/11-restart/08-side-restart.json @@ -6,7 +6,7 @@ }, "incremental": { "reluctant": { - "on": false + "enabled": false } }, "solvers": { diff --git a/tests/incremental/13-restart-write/06-mutex-simple-reluctant.json b/tests/incremental/13-restart-write/06-mutex-simple-reluctant.json index 699332fa16..e9d2a403fe 100644 --- a/tests/incremental/13-restart-write/06-mutex-simple-reluctant.json +++ b/tests/incremental/13-restart-write/06-mutex-simple-reluctant.json @@ -6,7 +6,7 @@ } }, "reluctant": { - "on": true + "enabled": true } } } \ No newline at end of file diff --git a/tests/incremental/13-restart-write/07-mutex-simple-reluctant2.json b/tests/incremental/13-restart-write/07-mutex-simple-reluctant2.json index 36c62c6389..74bc650477 100644 --- a/tests/incremental/13-restart-write/07-mutex-simple-reluctant2.json +++ b/tests/incremental/13-restart-write/07-mutex-simple-reluctant2.json @@ -6,7 +6,7 @@ } }, "reluctant": { - "on": true + "enabled": true } } } diff --git a/tests/incremental/13-restart-write/08-mutex-simple-reluctant3.json b/tests/incremental/13-restart-write/08-mutex-simple-reluctant3.json index 699332fa16..e9d2a403fe 100644 --- a/tests/incremental/13-restart-write/08-mutex-simple-reluctant3.json +++ b/tests/incremental/13-restart-write/08-mutex-simple-reluctant3.json @@ -6,7 +6,7 @@ } }, "reluctant": { - "on": true + "enabled": true } } } \ No newline at end of file From dee744e372013fbfce9991705b5a25a9b7bf60d8 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 18 May 2022 17:20:24 +0300 Subject: [PATCH 383/402] Renumber incremental fuel tests --- .../{13-mutex-simple-wrap2.c => 14-mutex-simple-wrap2.c} | 0 ...{13-mutex-simple-wrap2.json => 14-mutex-simple-wrap2.json} | 0 ...3-mutex-simple-wrap2.patch => 14-mutex-simple-wrap2.patch} | 4 ++-- .../{14-mutex-simple-wrap1.c => 15-mutex-simple-wrap1.c} | 0 ...{14-mutex-simple-wrap1.json => 15-mutex-simple-wrap1.json} | 0 ...4-mutex-simple-wrap1.patch => 15-mutex-simple-wrap1.patch} | 4 ++-- ...x-simple-wrap1-global.c => 16-mutex-simple-wrap1-global.c} | 0 ...le-wrap1-global.json => 16-mutex-simple-wrap1-global.json} | 0 ...-wrap1-global.patch => 16-mutex-simple-wrap1-global.patch} | 4 ++-- 9 files changed, 6 insertions(+), 6 deletions(-) rename tests/incremental/11-restart/{13-mutex-simple-wrap2.c => 14-mutex-simple-wrap2.c} (100%) rename tests/incremental/11-restart/{13-mutex-simple-wrap2.json => 14-mutex-simple-wrap2.json} (100%) rename tests/incremental/11-restart/{13-mutex-simple-wrap2.patch => 14-mutex-simple-wrap2.patch} (81%) rename tests/incremental/11-restart/{14-mutex-simple-wrap1.c => 15-mutex-simple-wrap1.c} (100%) rename tests/incremental/11-restart/{14-mutex-simple-wrap1.json => 15-mutex-simple-wrap1.json} (100%) rename tests/incremental/11-restart/{14-mutex-simple-wrap1.patch => 15-mutex-simple-wrap1.patch} (81%) rename tests/incremental/11-restart/{15-mutex-simple-wrap1-global.c => 16-mutex-simple-wrap1-global.c} (100%) rename tests/incremental/11-restart/{15-mutex-simple-wrap1-global.json => 16-mutex-simple-wrap1-global.json} (100%) rename tests/incremental/11-restart/{15-mutex-simple-wrap1-global.patch => 16-mutex-simple-wrap1-global.patch} (79%) diff --git a/tests/incremental/11-restart/13-mutex-simple-wrap2.c b/tests/incremental/11-restart/14-mutex-simple-wrap2.c similarity index 100% rename from tests/incremental/11-restart/13-mutex-simple-wrap2.c rename to tests/incremental/11-restart/14-mutex-simple-wrap2.c diff --git a/tests/incremental/11-restart/13-mutex-simple-wrap2.json b/tests/incremental/11-restart/14-mutex-simple-wrap2.json similarity index 100% rename from tests/incremental/11-restart/13-mutex-simple-wrap2.json rename to tests/incremental/11-restart/14-mutex-simple-wrap2.json diff --git a/tests/incremental/11-restart/13-mutex-simple-wrap2.patch b/tests/incremental/11-restart/14-mutex-simple-wrap2.patch similarity index 81% rename from tests/incremental/11-restart/13-mutex-simple-wrap2.patch rename to tests/incremental/11-restart/14-mutex-simple-wrap2.patch index 075513aea3..e11e3e3d3c 100644 --- a/tests/incremental/11-restart/13-mutex-simple-wrap2.patch +++ b/tests/incremental/11-restart/14-mutex-simple-wrap2.patch @@ -1,5 +1,5 @@ ---- tests/incremental/11-restart/13-mutex-simple-wrap2.c -+++ tests/incremental/11-restart/13-mutex-simple-wrap2.c +--- tests/incremental/11-restart/14-mutex-simple-wrap2.c ++++ tests/incremental/11-restart/14-mutex-simple-wrap2.c @@ -7,15 +7,15 @@ pthread_mutex_t mutex2 = PTHREAD_MUTEX_INITIALIZER; void *t_fun(void *arg) { diff --git a/tests/incremental/11-restart/14-mutex-simple-wrap1.c b/tests/incremental/11-restart/15-mutex-simple-wrap1.c similarity index 100% rename from tests/incremental/11-restart/14-mutex-simple-wrap1.c rename to tests/incremental/11-restart/15-mutex-simple-wrap1.c diff --git a/tests/incremental/11-restart/14-mutex-simple-wrap1.json b/tests/incremental/11-restart/15-mutex-simple-wrap1.json similarity index 100% rename from tests/incremental/11-restart/14-mutex-simple-wrap1.json rename to tests/incremental/11-restart/15-mutex-simple-wrap1.json diff --git a/tests/incremental/11-restart/14-mutex-simple-wrap1.patch b/tests/incremental/11-restart/15-mutex-simple-wrap1.patch similarity index 81% rename from tests/incremental/11-restart/14-mutex-simple-wrap1.patch rename to tests/incremental/11-restart/15-mutex-simple-wrap1.patch index 191f1771f9..b4ff89ef71 100644 --- a/tests/incremental/11-restart/14-mutex-simple-wrap1.patch +++ b/tests/incremental/11-restart/15-mutex-simple-wrap1.patch @@ -1,5 +1,5 @@ ---- tests/incremental/11-restart/14-mutex-simple-wrap1.c -+++ tests/incremental/11-restart/14-mutex-simple-wrap1.c +--- tests/incremental/11-restart/15-mutex-simple-wrap1.c ++++ tests/incremental/11-restart/15-mutex-simple-wrap1.c @@ -7,15 +7,15 @@ pthread_mutex_t mutex2 = PTHREAD_MUTEX_INITIALIZER; void *t_fun(void *arg) { diff --git a/tests/incremental/11-restart/15-mutex-simple-wrap1-global.c b/tests/incremental/11-restart/16-mutex-simple-wrap1-global.c similarity index 100% rename from tests/incremental/11-restart/15-mutex-simple-wrap1-global.c rename to tests/incremental/11-restart/16-mutex-simple-wrap1-global.c diff --git a/tests/incremental/11-restart/15-mutex-simple-wrap1-global.json b/tests/incremental/11-restart/16-mutex-simple-wrap1-global.json similarity index 100% rename from tests/incremental/11-restart/15-mutex-simple-wrap1-global.json rename to tests/incremental/11-restart/16-mutex-simple-wrap1-global.json diff --git a/tests/incremental/11-restart/15-mutex-simple-wrap1-global.patch b/tests/incremental/11-restart/16-mutex-simple-wrap1-global.patch similarity index 79% rename from tests/incremental/11-restart/15-mutex-simple-wrap1-global.patch rename to tests/incremental/11-restart/16-mutex-simple-wrap1-global.patch index 4d0c246660..5fdd33c2bf 100644 --- a/tests/incremental/11-restart/15-mutex-simple-wrap1-global.patch +++ b/tests/incremental/11-restart/16-mutex-simple-wrap1-global.patch @@ -1,5 +1,5 @@ ---- tests/incremental/11-restart/15-mutex-simple-wrap1-global.c -+++ tests/incremental/11-restart/15-mutex-simple-wrap1-global.c +--- tests/incremental/11-restart/16-mutex-simple-wrap1-global.c ++++ tests/incremental/11-restart/16-mutex-simple-wrap1-global.c @@ -7,15 +7,15 @@ pthread_mutex_t mutex2 = PTHREAD_MUTEX_INITIALIZER; void *t_fun(void *arg) { From 99f8b206d0425232ab2fa0bf1a76affed9359bc0 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 18 May 2022 17:28:42 +0300 Subject: [PATCH 384/402] Fix incremental fuel tests by adding option incremental.restart.write-only --- src/solvers/td3.ml | 19 ++++++++++++------- src/util/options.schema.json | 6 ++++++ .../11-restart/14-mutex-simple-wrap2.json | 3 ++- .../11-restart/15-mutex-simple-wrap1.json | 3 ++- .../16-mutex-simple-wrap1-global.json | 3 ++- 5 files changed, 24 insertions(+), 10 deletions(-) diff --git a/src/solvers/td3.ml b/src/solvers/td3.ml index 889ff09cbc..2f6d08e0c5 100644 --- a/src/solvers/td3.ml +++ b/src/solvers/td3.ml @@ -366,6 +366,8 @@ module WP = (* reluctantly unchanged return nodes to additionally query for postsolving to get warnings, etc. *) let reluctant_vs: S.Var.t list ref = ref [] in + let restart_write_only = GobConfig.get_bool "incremental.restart.write-only" in + if GobConfig.get_bool "incremental.load" then ( let c = S.increment.changes in List.(Printf.printf "change_info = { unchanged = %d; changed = %d; added = %d; removed = %d }\n" (length c.unchanged) (length c.changed) (length c.added) (length c.removed)); @@ -401,7 +403,7 @@ module WP = if restart_only_access then S.Var.is_write_only x else - (not restart_only_globals || Node.equal (S.Var.node x) (Function Cil.dummyFunDec)) && (not (S.Var.is_write_only x)) + (not restart_only_globals || Node.equal (S.Var.node x) (Function Cil.dummyFunDec)) && (not (S.Var.is_write_only x) || not restart_write_only) in if not (VS.is_empty w) && should_restart then ( @@ -874,12 +876,15 @@ module WP = HM.create 0 (* doesn't matter, not used *) in - (* restart write-only *) - HM.iter (fun x w -> - HM.iter (fun y d -> - HM.replace rho y (S.Dom.bot ()); - ) w - ) rho_write; + if restart_write_only then ( + (* restart write-only *) + HM.iter (fun x w -> + HM.iter (fun y d -> + ignore (Pretty.printf "Restarting write-only to bot %a\n" S.Var.pretty_trace y); + HM.replace rho y (S.Dom.bot ()); + ) w + ) rho_write + ); if incr_verify then ( HM.filteri_inplace (fun x _ -> HM.mem reachable_and_superstable x) var_messages; diff --git a/src/util/options.schema.json b/src/util/options.schema.json index a9d73a2f86..09df85f7f6 100644 --- a/src/util/options.schema.json +++ b/src/util/options.schema.json @@ -1086,6 +1086,12 @@ "type": "string" }, "default": [] + }, + "write-only": { + "title": "incremental.restart.write-only", + "description": "TODO", + "type": "boolean", + "default": true } }, "additionalProperties": false diff --git a/tests/incremental/11-restart/14-mutex-simple-wrap2.json b/tests/incremental/11-restart/14-mutex-simple-wrap2.json index 7775710988..6caf371761 100644 --- a/tests/incremental/11-restart/14-mutex-simple-wrap2.json +++ b/tests/incremental/11-restart/14-mutex-simple-wrap2.json @@ -4,7 +4,8 @@ "sided": { "enabled": true, "fuel": 2 - } + }, + "write-only": false } } } \ No newline at end of file diff --git a/tests/incremental/11-restart/15-mutex-simple-wrap1.json b/tests/incremental/11-restart/15-mutex-simple-wrap1.json index ec32980a50..92c18ab381 100644 --- a/tests/incremental/11-restart/15-mutex-simple-wrap1.json +++ b/tests/incremental/11-restart/15-mutex-simple-wrap1.json @@ -4,7 +4,8 @@ "sided": { "enabled": true, "fuel": 1 - } + }, + "write-only": false } } } \ No newline at end of file diff --git a/tests/incremental/11-restart/16-mutex-simple-wrap1-global.json b/tests/incremental/11-restart/16-mutex-simple-wrap1-global.json index b597867546..403fe4615c 100644 --- a/tests/incremental/11-restart/16-mutex-simple-wrap1-global.json +++ b/tests/incremental/11-restart/16-mutex-simple-wrap1-global.json @@ -5,7 +5,8 @@ "enabled": true, "fuel": 1, "fuel-only-global": true - } + }, + "write-only": false } } } \ No newline at end of file From 49cd2ce965c0b3189715c7a39fa731cabe073a98 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 18 May 2022 17:31:23 +0300 Subject: [PATCH 385/402] Revert fuel change to incremental 13-restart-write/01-mutex-simple Adds copy of test with fuel instead. --- .../11-restart/17-mutex-simple-fuel.c | 23 ++++++++++++++++++ .../11-restart/17-mutex-simple-fuel.json | 11 +++++++++ .../11-restart/17-mutex-simple-fuel.patch | 24 +++++++++++++++++++ .../13-restart-write/01-mutex-simple.json | 3 +-- 4 files changed, 59 insertions(+), 2 deletions(-) create mode 100644 tests/incremental/11-restart/17-mutex-simple-fuel.c create mode 100644 tests/incremental/11-restart/17-mutex-simple-fuel.json create mode 100644 tests/incremental/11-restart/17-mutex-simple-fuel.patch diff --git a/tests/incremental/11-restart/17-mutex-simple-fuel.c b/tests/incremental/11-restart/17-mutex-simple-fuel.c new file mode 100644 index 0000000000..82c1642a93 --- /dev/null +++ b/tests/incremental/11-restart/17-mutex-simple-fuel.c @@ -0,0 +1,23 @@ +#include +#include + +int myglobal; +pthread_mutex_t mutex1 = PTHREAD_MUTEX_INITIALIZER; +pthread_mutex_t mutex2 = PTHREAD_MUTEX_INITIALIZER; + +void *t_fun(void *arg) { + pthread_mutex_lock(&mutex1); + myglobal=myglobal+1; // RACE! + pthread_mutex_unlock(&mutex1); + return NULL; +} + +int main(void) { + pthread_t id; + pthread_create(&id, NULL, t_fun, NULL); + pthread_mutex_lock(&mutex2); + myglobal=myglobal+1; // RACE! + pthread_mutex_unlock(&mutex2); + pthread_join (id, NULL); + return 0; +} diff --git a/tests/incremental/11-restart/17-mutex-simple-fuel.json b/tests/incremental/11-restart/17-mutex-simple-fuel.json new file mode 100644 index 0000000000..92c18ab381 --- /dev/null +++ b/tests/incremental/11-restart/17-mutex-simple-fuel.json @@ -0,0 +1,11 @@ +{ + "incremental": { + "restart": { + "sided": { + "enabled": true, + "fuel": 1 + }, + "write-only": false + } + } +} \ No newline at end of file diff --git a/tests/incremental/11-restart/17-mutex-simple-fuel.patch b/tests/incremental/11-restart/17-mutex-simple-fuel.patch new file mode 100644 index 0000000000..cd26774267 --- /dev/null +++ b/tests/incremental/11-restart/17-mutex-simple-fuel.patch @@ -0,0 +1,24 @@ +--- tests/incremental/11-restart/17-mutex-simple-fuel.c ++++ tests/incremental/11-restart/17-mutex-simple-fuel.c +@@ -7,7 +7,7 @@ pthread_mutex_t mutex2 = PTHREAD_MUTEX_INITIALIZER; + + void *t_fun(void *arg) { + pthread_mutex_lock(&mutex1); +- myglobal=myglobal+1; // RACE! ++ myglobal=myglobal+1; // NORACE + pthread_mutex_unlock(&mutex1); + return NULL; + } +@@ -15,9 +15,9 @@ void *t_fun(void *arg) { + int main(void) { + pthread_t id; + pthread_create(&id, NULL, t_fun, NULL); +- pthread_mutex_lock(&mutex2); +- myglobal=myglobal+1; // RACE! +- pthread_mutex_unlock(&mutex2); ++ pthread_mutex_lock(&mutex1); ++ myglobal=myglobal+1; // NORACE ++ pthread_mutex_unlock(&mutex1); + pthread_join (id, NULL); + return 0; + } diff --git a/tests/incremental/13-restart-write/01-mutex-simple.json b/tests/incremental/13-restart-write/01-mutex-simple.json index ec32980a50..daff0678ce 100644 --- a/tests/incremental/13-restart-write/01-mutex-simple.json +++ b/tests/incremental/13-restart-write/01-mutex-simple.json @@ -2,8 +2,7 @@ "incremental": { "restart": { "sided": { - "enabled": true, - "fuel": 1 + "enabled": false } } } From 77b3fca82491012c492f229de2a85d4cd1eb20a9 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 18 May 2022 17:49:16 +0300 Subject: [PATCH 386/402] Add descriptions to fuel options --- src/util/options.schema.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/util/options.schema.json b/src/util/options.schema.json index 09df85f7f6..76b972d13e 100644 --- a/src/util/options.schema.json +++ b/src/util/options.schema.json @@ -1047,7 +1047,7 @@ }, "only-global": { "title": "incremental.restart.sided.only-global", - "description": "Restart only constraint system globals.", + "description": "Restart only constraint system globals (not function entry nodes).", "type": "boolean", "default": false }, @@ -1065,13 +1065,13 @@ }, "fuel": { "title": "incremental.restart.sided.fuel", - "description": "TODO", + "description": "Initial fuel for bounding transitive restarting, which uses one fuel each time when following side_fuel to restart. Zero fuel never restarts. Negative fuel doesn't bound (infinite fuel).", "type": "integer", "default": -1 }, "fuel-only-global": { "title": "incremental.restart.sided.fuel-only-global", - "description": "TODO", + "description": "Decrease fuel only when going to constraint system globals (not function entry nodes).", "type": "boolean", "default": false } @@ -1089,7 +1089,7 @@ }, "write-only": { "title": "incremental.restart.write-only", - "description": "TODO", + "description": "Restart write-only variables to bot during postprocessing.", "type": "boolean", "default": true } From c491dbba47f257ce6f2e296cf48533195a22799b Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 19 May 2022 15:37:22 +0300 Subject: [PATCH 387/402] Re-allow All threads must joined for chrony story, but warn about it --- scripts/update_suite.rb | 1 + src/analyses/apron/apronPriv.apron.ml | 8 ++++--- src/analyses/threadJoins.ml | 21 ++++++++++++------- .../51-threadjoins/05-assume-unknown.c | 5 ++++- 4 files changed, 24 insertions(+), 11 deletions(-) diff --git a/scripts/update_suite.rb b/scripts/update_suite.rb index a573208a21..06c4d4dda3 100755 --- a/scripts/update_suite.rb +++ b/scripts/update_suite.rb @@ -159,6 +159,7 @@ def collect_warnings when /Assertion .* is unknown/ then "unknown" when /^\[Warning\]/ then "warn" when /^\[Error\]/ then "warn" + when /^\[Info\]/ then "warn" when /\[Debug\]/ then next # debug "warnings" shouldn't count as other warnings (against NOWARN) when /^ on line \d+ $/ then next # dead line warnings shouldn't count (used for unreachability with NOWARN) when /^ on lines \d+..\d+ $/ then next # dead line warnings shouldn't count (used for unreachability with NOWARN) diff --git a/src/analyses/apron/apronPriv.apron.ml b/src/analyses/apron/apronPriv.apron.ml index 0959828fe1..86683a45d0 100644 --- a/src/analyses/apron/apronPriv.apron.ml +++ b/src/analyses/apron/apronPriv.apron.ml @@ -987,11 +987,13 @@ struct let w,lmust,l = st.priv in let tids = ask.f (Q.EvalThread exp) in if force then ( - if ConcDomain.ThreadSet.is_top tids then - st (* don't consider anything more joined, matches threadJoins analysis *) + if ConcDomain.ThreadSet.is_top tids then ( + M.info ~category:Unsound "Unknown thread ID assume-joined, Apron privatization unsound"; (* TODO: something more sound *) + st (* cannot find all thread IDs to join them all *) + ) else ( (* fold throws if the thread set is top *) - let tids' = ConcDomain.ThreadSet.diff tids (ask.f Q.MustJoinedThreads) in (* avoid unnecessary imprecision by force joining already must-joined threas, e.g. 46-apron2/04-other-assume-inprec *) + let tids' = ConcDomain.ThreadSet.diff tids (ask.f Q.MustJoinedThreads) in (* avoid unnecessary imprecision by force joining already must-joined threads, e.g. 46-apron2/04-other-assume-inprec *) let (lmust', l') = ConcDomain.ThreadSet.fold (fun tid (lmust, l) -> let lmust',l' = G.thread (getg (V.thread tid)) in (LMust.union lmust' lmust, L.join l l') diff --git a/src/analyses/threadJoins.ml b/src/analyses/threadJoins.ml index c85061de71..488e573e31 100644 --- a/src/analyses/threadJoins.ml +++ b/src/analyses/threadJoins.ml @@ -48,8 +48,10 @@ struct | `Unknown "__goblint_assume_join" -> let id = List.hd arglist in let threads = ctx.ask (Queries.EvalThread id) in - if TIDs.is_top threads then - ctx.local (* don't consider everything joined, because would be confusing to have All threads unsoundly joined due to imprecision *) + if TIDs.is_top threads then ( + M.info ~category:Unsound "Unknown thread ID assume-joined, assuming ALL threads must-joined."; + D.bot () (* consider everything joined, D is reversed so bot is All threads *) + ) else ( (* elements throws if the thread set is top *) let threads = TIDs.elements threads in @@ -61,11 +63,16 @@ struct | _ -> ctx.local let threadspawn ctx lval f args fctx = - match ThreadId.get_current (Analyses.ask_of_ctx fctx) with - | `Lifted tid -> - D.remove tid ctx.local - | _ -> - ctx.local + if D.is_bot ctx.local then ( (* bot is All threads *) + M.info ~category:Imprecise "Thread created while ALL threads must-joined, continuing with no threads joined."; + D.top () (* top is no threads *) + ) + else + match ThreadId.get_current (Analyses.ask_of_ctx fctx) with + | `Lifted tid -> + D.remove tid ctx.local + | _ -> + ctx.local let query ctx (type a) (q: a Queries.t): a Queries.result = match q with diff --git a/tests/regression/51-threadjoins/05-assume-unknown.c b/tests/regression/51-threadjoins/05-assume-unknown.c index d870918240..7c113715cd 100644 --- a/tests/regression/51-threadjoins/05-assume-unknown.c +++ b/tests/regression/51-threadjoins/05-assume-unknown.c @@ -13,8 +13,11 @@ int main() { pthread_t id, id2; pthread_create(&id, NULL, t_fun, NULL); - __goblint_assume_join(id2); // joining unknown thread ID, shouldn't make joined set All threads + __goblint_assume_join(id2); // WARN joining unknown thread ID, make joined set All threads + g++; // NORACE + + pthread_create(&id, NULL, t_fun, NULL); // WARN make joined set different from All threads g++; // RACE! return 0; From 41d3cd4dbef0fab7c67d54544bb4a41b21bec065 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 19 May 2022 17:19:05 +0300 Subject: [PATCH 388/402] Fix var_eq eq_set_clos indentation (PR #724) --- src/analyses/varEq.ml | 62 +++++++++++++++++++++---------------------- 1 file changed, 31 insertions(+), 31 deletions(-) diff --git a/src/analyses/varEq.ml b/src/analyses/varEq.ml index dfde1a3de8..072cbf3079 100644 --- a/src/analyses/varEq.ml +++ b/src/analyses/varEq.ml @@ -530,37 +530,37 @@ struct let rec eq_set_clos e s = if M.tracing then M.traceli "var_eq" "eq_set_clos %a\n" d_plainexp e; let r = match e with - | AddrOf (Mem (BinOp (IndexPI, a, i, _)), os) -> - (* convert IndexPI to Index offset *) - (* TODO: this applies eq_set_clos under the offset, unlike cases below; should generalize? *) - Queries.ES.fold (fun e acc -> (* filter_map *) - match e with - | CastE (_, StartOf a') -> (* eq_set adds casts *) - let e' = AddrOf (Cil.addOffsetLval (Index (i, os)) a') in (* TODO: re-add cast? *) - Queries.ES.add e' acc - | _ -> acc - ) (eq_set_clos a s) (Queries.ES.empty ()) - | SizeOf _ - | SizeOfE _ - | SizeOfStr _ - | AlignOf _ - | Const _ - | AlignOfE _ - | UnOp _ - | BinOp _ - | AddrOf (Var _,_) - | StartOf (Var _,_) - | Lval (Var _,_) -> eq_set e s - | AddrOf (Mem e,ofs) -> - Queries.ES.map (fun e -> mkAddrOf (mkMem ~addr:e ~off:ofs)) (eq_set_clos e s) - | StartOf (Mem e,ofs) -> - Queries.ES.map (fun e -> mkAddrOrStartOf (mkMem ~addr:e ~off:ofs)) (eq_set_clos e s) - | Lval (Mem e,ofs) -> - Queries.ES.map (fun e -> Lval (mkMem ~addr:e ~off:ofs)) (eq_set_clos e s) - | CastE (t,e) -> - Queries.ES.map (fun e -> CastE (t,e)) (eq_set_clos e s) - | Question _ -> failwith "Logical operations should be compiled away by CIL." - | _ -> failwith "Unmatched pattern." + | AddrOf (Mem (BinOp (IndexPI, a, i, _)), os) -> + (* convert IndexPI to Index offset *) + (* TODO: this applies eq_set_clos under the offset, unlike cases below; should generalize? *) + Queries.ES.fold (fun e acc -> (* filter_map *) + match e with + | CastE (_, StartOf a') -> (* eq_set adds casts *) + let e' = AddrOf (Cil.addOffsetLval (Index (i, os)) a') in (* TODO: re-add cast? *) + Queries.ES.add e' acc + | _ -> acc + ) (eq_set_clos a s) (Queries.ES.empty ()) + | SizeOf _ + | SizeOfE _ + | SizeOfStr _ + | AlignOf _ + | Const _ + | AlignOfE _ + | UnOp _ + | BinOp _ + | AddrOf (Var _,_) + | StartOf (Var _,_) + | Lval (Var _,_) -> eq_set e s + | AddrOf (Mem e,ofs) -> + Queries.ES.map (fun e -> mkAddrOf (mkMem ~addr:e ~off:ofs)) (eq_set_clos e s) + | StartOf (Mem e,ofs) -> + Queries.ES.map (fun e -> mkAddrOrStartOf (mkMem ~addr:e ~off:ofs)) (eq_set_clos e s) + | Lval (Mem e,ofs) -> + Queries.ES.map (fun e -> Lval (mkMem ~addr:e ~off:ofs)) (eq_set_clos e s) + | CastE (t,e) -> + Queries.ES.map (fun e -> CastE (t,e)) (eq_set_clos e s) + | Question _ -> failwith "Logical operations should be compiled away by CIL." + | _ -> failwith "Unmatched pattern." in if M.tracing then M.traceu "var_eq" "eq_set_clos %a = %a\n" d_plainexp e Queries.ES.pretty r; r From da790e094cfaa522e5621cf8703a1f01afeee390 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 19 May 2022 17:24:12 +0300 Subject: [PATCH 389/402] Fix more var_eq eq_set_clos indentation (PR #724) --- src/analyses/varEq.ml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/analyses/varEq.ml b/src/analyses/varEq.ml index 072cbf3079..40350e7e5e 100644 --- a/src/analyses/varEq.ml +++ b/src/analyses/varEq.ml @@ -534,12 +534,12 @@ struct (* convert IndexPI to Index offset *) (* TODO: this applies eq_set_clos under the offset, unlike cases below; should generalize? *) Queries.ES.fold (fun e acc -> (* filter_map *) - match e with - | CastE (_, StartOf a') -> (* eq_set adds casts *) - let e' = AddrOf (Cil.addOffsetLval (Index (i, os)) a') in (* TODO: re-add cast? *) - Queries.ES.add e' acc - | _ -> acc - ) (eq_set_clos a s) (Queries.ES.empty ()) + match e with + | CastE (_, StartOf a') -> (* eq_set adds casts *) + let e' = AddrOf (Cil.addOffsetLval (Index (i, os)) a') in (* TODO: re-add cast? *) + Queries.ES.add e' acc + | _ -> acc + ) (eq_set_clos a s) (Queries.ES.empty ()) | SizeOf _ | SizeOfE _ | SizeOfStr _ From 3d9bf4b6925db55955ca04b2976b97bd2d936b9b Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 19 May 2022 17:46:13 +0300 Subject: [PATCH 390/402] Add server command pre_files (closes #739) --- src/util/server.ml | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/util/server.ml b/src/util/server.ml index 808b351cdb..3d41f7b7ec 100644 --- a/src/util/server.ml +++ b/src/util/server.ml @@ -232,6 +232,18 @@ let () = let process () _ = Preprocessor.dependencies_to_yojson () end); + register (module struct + let name = "pre_files" + type params = unit [@@deriving of_yojson] + type response = Yojson.Safe.t [@@deriving to_yojson] + let process () s = + if GobConfig.get_bool "server.reparse" then ( + GoblintDir.init (); + ignore (Fun.protect ~finally:GoblintDir.finalize Maingoblint.preprocess_and_merge) + ); + Preprocessor.dependencies_to_yojson () + end); + register (module struct let name = "exp_eval" type params = ExpressionEvaluation.query [@@deriving of_yojson] From f60b16ccec65954dd6f851f53f66c24fe2b23604 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 19 May 2022 17:54:32 +0300 Subject: [PATCH 391/402] Optimize server pre_files by not merging files --- src/goblint.ml | 2 +- src/maingoblint.ml | 15 ++++++++++----- src/util/server.ml | 6 ++++-- 3 files changed, 15 insertions(+), 8 deletions(-) diff --git a/src/goblint.ml b/src/goblint.ml index d7ad205b3e..a667f40afd 100644 --- a/src/goblint.ml +++ b/src/goblint.ml @@ -23,7 +23,7 @@ let main () = print_endline (localtime ()); print_endline command; ); - let file = lazy (Fun.protect ~finally:GoblintDir.finalize preprocess_and_merge) in + let file = lazy (Fun.protect ~finally:GoblintDir.finalize preprocess_parse_merge) in if get_bool "server.enabled" then ( let file = if get_bool "server.reparse" then diff --git a/src/maingoblint.ml b/src/maingoblint.ml index ce3ce95cd6..d1fa834331 100644 --- a/src/maingoblint.ml +++ b/src/maingoblint.ml @@ -332,8 +332,8 @@ let preprocess_files () = ); preprocessed -(** Possibly merge all postprocessed files *) -let merge_preprocessed preprocessed = +(** Parse preprocessed files *) +let parse_preprocessed preprocessed = (* get the AST *) if get_bool "dbg.verbose" then print_endline "Parsing files."; @@ -358,8 +358,10 @@ let merge_preprocessed preprocessed = Cilfacade.getAST preprocessed_file in - let files_AST = List.map (get_ast_and_record_deps) preprocessed in + List.map get_ast_and_record_deps preprocessed +(** Merge parsed files *) +let merge_parsed parsed = let cilout = if get_string "dbg.cilout" = "" then Legacy.stderr else Legacy.open_out (get_string "dbg.cilout") in @@ -368,7 +370,7 @@ let merge_preprocessed preprocessed = (* we use CIL to merge all inputs to ONE file *) let merged_AST = - match files_AST with + match parsed with | [one] -> Cilfacade.callConstructors one | [] -> prerr_endline "No files to analyze!"; @@ -383,7 +385,10 @@ let merge_preprocessed preprocessed = Cilfacade.current_file := merged_AST; merged_AST -let preprocess_and_merge () = preprocess_files () |> merge_preprocessed +let preprocess_parse_merge () = + preprocess_files () + |> parse_preprocessed + |> merge_parsed let do_stats () = if get_bool "printstats" then ( diff --git a/src/util/server.ml b/src/util/server.ml index 3d41f7b7ec..5d185f86f7 100644 --- a/src/util/server.ml +++ b/src/util/server.ml @@ -119,7 +119,7 @@ let start file = let reparse (s: t) = if GobConfig.get_bool "server.reparse" then ( GoblintDir.init (); - let file = Fun.protect ~finally:GoblintDir.finalize Maingoblint.preprocess_and_merge in + let file = Fun.protect ~finally:GoblintDir.finalize Maingoblint.preprocess_parse_merge in begin match s.file with | None -> let max_ids = MaxIdUtil.get_file_max_ids file in @@ -239,7 +239,9 @@ let () = let process () s = if GobConfig.get_bool "server.reparse" then ( GoblintDir.init (); - ignore (Fun.protect ~finally:GoblintDir.finalize Maingoblint.preprocess_and_merge) + Fun.protect ~finally:GoblintDir.finalize (fun () -> + ignore Maingoblint.(preprocess_files () |> parse_preprocessed) + ) ); Preprocessor.dependencies_to_yojson () end); From edd5c1de0b6009f4b2e03d5c0a2defbe529b77ce Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Mon, 20 Jun 2022 11:40:41 +0300 Subject: [PATCH 392/402] Fix 34-localwn_restart/04-hh PARAMs --- tests/regression/34-localwn_restart/04-hh.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/regression/34-localwn_restart/04-hh.c b/tests/regression/34-localwn_restart/04-hh.c index 4f784bac6c..5866e7a2ee 100644 --- a/tests/regression/34-localwn_restart/04-hh.c +++ b/tests/regression/34-localwn_restart/04-hh.c @@ -1,7 +1,7 @@ -// SKIP PARAM: --enable ana.int.interval --set solver td3 --set ana.base.arrays.domain partitioned --set ana.activated "['base','threadid','threadflag','expRelation','mallocWrapper','apron']" --set ana.base.privatization none --set ana.apron.privatization dummy --set sem.int.signed_overflow assume_none +// SKIP PARAM: --enable ana.int.interval --set solver td3 --set ana.activated[+] apron --set sem.int.signed_overflow assume_none // This is part of 34-localization, but also symlinked to 36-apron. -// ALSO: --enable ana.int.interval --set solver slr3 --set ana.base.arrays.domain partitioned --set ana.activated "['base','threadid','threadflag','expRelation','mallocWrapper','apron']" --set ana.base.privatization none --set ana.apron.privatization dummy --set sem.int.signed_overflow assume_none +// ALSO: --enable ana.int.interval --set solver slr3 --set ana.activated[+] apron --set sem.int.signed_overflow assume_none // Example from Halbwachs-Henry, SAS 2012 // Localized widening or restart policy should be able to prove that i <= j+3 // if the abstract domain is powerful enough. From 7b8e34646f1a4c0dc95dbf87e92972fa707d2fac Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 3 Aug 2022 12:52:00 +0300 Subject: [PATCH 393/402] Add info about assume-joining ambiguous thread ID https://github.com/goblint/analyzer/pull/391#discussion_r935258191 --- src/analyses/threadJoins.ml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/analyses/threadJoins.ml b/src/analyses/threadJoins.ml index 9db4d99d2a..494a86262b 100644 --- a/src/analyses/threadJoins.ml +++ b/src/analyses/threadJoins.ml @@ -56,6 +56,8 @@ struct else ( (* elements throws if the thread set is top *) let threads = TIDs.elements threads in + if List.compare_length_with threads 1 > 0 then + M.info ~category:Unsound "Ambiguous thread ID assume-joined, assuming all of those threads must-joined."; List.fold_left (fun acc tid -> let joined = ctx.global tid in D.union (D.add tid acc) joined From 9d1e8ad0fa30b27a4c2f449d77409eb7435f7dbd Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 4 Aug 2022 11:26:19 +0300 Subject: [PATCH 394/402] Fix indentation after merge --- src/analyses/base.ml | 4 ++-- src/incremental/compareCIL.ml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/analyses/base.ml b/src/analyses/base.ml index e38a94a3fa..9e5179e1d8 100644 --- a/src/analyses/base.ml +++ b/src/analyses/base.ml @@ -2516,8 +2516,8 @@ struct | "__builtin___memcpy_chk", [dst; src; _; _] -> (* invalidating from interactive *) (* let dest_a, dest_typ = addr_type_of_exp dst in - let value = VD.top_value dest_typ in - set ~ctx (Analyses.ask_of_ctx ctx) gs st dest_a dest_typ value *) + let value = VD.top_value dest_typ in + set ~ctx (Analyses.ask_of_ctx ctx) gs st dest_a dest_typ value *) (* assigning from master *) let dst_lval = mkMem ~addr:(Cil.stripCasts dst) ~off:NoOffset in let src_a = mkMem ~addr:(Cil.stripCasts src) ~off:NoOffset in diff --git a/src/incremental/compareCIL.ml b/src/incremental/compareCIL.ml index 8ae7c70f6f..991ca502a4 100644 --- a/src/incremental/compareCIL.ml +++ b/src/incremental/compareCIL.ml @@ -60,7 +60,7 @@ let eqF (old: Cil.fundec) (current: Cil.fundec) (cfgs : (cfg * (cfg * cfg)) opti let emptyRenameMapping = (StringMap.empty, VarinfoMap.empty) in (* Compares the two varinfo lists, returning as a first element, if the size of the two lists are equal, - * and as a second a rename_mapping, holding the rename assumptions *) + and as a second a rename_mapping, holding the rename assumptions *) let rec rename_mapping_aware_compare (alocals: varinfo list) (blocals: varinfo list) (rename_mapping: string StringMap.t) = match alocals, blocals with | [], [] -> true, rename_mapping | origLocal :: als, nowLocal :: bls -> From 9dd1ded153a71ba04f7f5e27dc5286f722aef8a4 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 4 Aug 2022 11:30:56 +0300 Subject: [PATCH 395/402] Remove solvers.td3.narrow-reuse-verify This was for debugging TD3 aborting not interacting well with narrow reuse. --- src/solvers/td3.ml | 10 +--------- src/util/options.schema.json | 6 ------ 2 files changed, 1 insertion(+), 15 deletions(-) diff --git a/src/solvers/td3.ml b/src/solvers/td3.ml index 2f6d08e0c5..85df1c572b 100644 --- a/src/solvers/td3.ml +++ b/src/solvers/td3.ml @@ -99,7 +99,6 @@ module WP = let stable = data.stable in let narrow_reuse = GobConfig.get_bool "solvers.td3.narrow-reuse" in - let narrow_reuse_verify = GobConfig.get_bool "solvers.td3.narrow-reuse-verify" in let side_dep = data.side_dep in let side_infl = data.side_infl in @@ -172,7 +171,7 @@ module WP = let l = HM.create 10 in let tmp = match reuse_eq with - | Some d when narrow_reuse && not narrow_reuse_verify -> + | Some d when narrow_reuse -> (* Do not reset deps for reuse of eq *) if tracing then trace "sol2" "eq reused %a\n" S.Var.pretty_trace x; incr Goblintutil.narrow_reuses; @@ -182,13 +181,6 @@ module WP = HM.replace dep x VS.empty; eq x (eval l x) (side ~x) in - begin match reuse_eq with - | Some reuse_eq when narrow_reuse_verify && not (S.Dom.equal tmp reuse_eq) -> - if M.tracing then trace "sol2" "reuse eq neq %a: %a %a\n" S.Var.pretty_trace x S.Dom.pretty reuse_eq S.Dom.pretty tmp; - failwith (Pretty.sprint ~width:max_int (Pretty.dprintf "TD3 narrow reuse verify: should not reuse %a" S.Var.pretty_trace x)) - | _ -> - () - end; let new_eq = tmp in (* let tmp = if GobConfig.get_bool "ana.opt.hashcons" then S.Dom.join (S.Dom.bot ()) tmp else tmp in (* Call hashcons via dummy join so that the tag of the rhs value is up to date. Otherwise we might get the same value as old, but still with a different tag (because no lattice operation was called after a change), and since Printable.HConsed.equal just looks at the tag, we would unnecessarily destabilize below. Seems like this does not happen. *) *) if tracing then trace "sol" "Var: %a\n" S.Var.pretty_trace x ; diff --git a/src/util/options.schema.json b/src/util/options.schema.json index 87adda73aa..05313345a9 100644 --- a/src/util/options.schema.json +++ b/src/util/options.schema.json @@ -1880,12 +1880,6 @@ "type": "boolean", "default": true }, - "narrow-reuse-verify": { - "title": "solvers.td3.narrow-reuse-verify", - "description": "Instead of reusing value when switching from widening to narrowing phase, just verify that the reuse would be correct by re-evaluating.", - "type": "boolean", - "default": false - }, "restart": { "title": "solvers.td3.restart", "type": "object", From 9f329fcf7bf12a960ce6a597c5129114cd9785b2 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 4 Aug 2022 12:18:12 +0300 Subject: [PATCH 396/402] Fix YamlWitness mismerge in d409f68c9fc2f939a2283c6eebb734119cd9cca3 --- src/witness/yamlWitness.ml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/witness/yamlWitness.ml b/src/witness/yamlWitness.ml index e951f72aec..8828da9375 100644 --- a/src/witness/yamlWitness.ml +++ b/src/witness/yamlWitness.ml @@ -141,7 +141,7 @@ struct ; context = (fun () -> ctx_failwith "No context in witness context.") ; edge = MyCFG.Skip ; local = local - ; global = (fun v -> try (fun g -> EQSys.G.spec (GHT.find gh (EQSys.GVar.spec g))) v with Not_found -> Spec.G.bot ()) (* TODO: how can be missing? *) + ; global = (fun g -> try EQSys.G.spec (GHT.find gh (EQSys.GVar.spec g)) with Not_found -> Spec.G.bot ()) (* TODO: how can be missing? *) ; spawn = (fun v d -> failwith "Cannot \"spawn\" in witness context.") ; split = (fun d es -> failwith "Cannot \"split\" in witness context.") ; sideg = (fun v g -> failwith "Cannot \"sideg\" in witness context.") From 7aa89e9b3b0e7f4a524c79e99ed4fa90a8945a85 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 4 Aug 2022 12:46:11 +0300 Subject: [PATCH 397/402] Remove broken incremental.restart.sided.destab-with-sides option https://github.com/goblint/analyzer/issues/703#issuecomment-1205016186 --- src/solvers/td3.ml | 6 +----- src/util/options.schema.json | 6 ------ tests/incremental/11-restart/12-mutex-simple-access.json | 5 +++-- tests/incremental/11-restart/13-changed_start_state2.json | 3 +-- 4 files changed, 5 insertions(+), 15 deletions(-) diff --git a/src/solvers/td3.ml b/src/solvers/td3.ml index 85df1c572b..c3877dfae8 100644 --- a/src/solvers/td3.ml +++ b/src/solvers/td3.ml @@ -105,7 +105,6 @@ module WP = let restart_sided = GobConfig.get_bool "incremental.restart.sided.enabled" in let restart_only_globals = GobConfig.get_bool "incremental.restart.sided.only-global" in let restart_only_access = GobConfig.get_bool "incremental.restart.sided.only-access" in - let restart_destab_with_sides = GobConfig.get_bool "incremental.restart.sided.destab-with-sides" in let restart_wpoint = GobConfig.get_bool "solvers.td3.restart.wpoint.enabled" in let restart_once = GobConfig.get_bool "solvers.td3.restart.wpoint.once" in @@ -408,10 +407,7 @@ module WP = if tracing then trace "sol2" "stable remove %a\n" S.Var.pretty_trace y; HM.remove stable y; HM.remove superstable y; - if restart_destab_with_sides then - destabilize_with_side ~side_fuel y - else - destabilize_normal y + destabilize_with_side ~side_fuel y ) w ); diff --git a/src/util/options.schema.json b/src/util/options.schema.json index 05313345a9..aee7b045ff 100644 --- a/src/util/options.schema.json +++ b/src/util/options.schema.json @@ -1019,12 +1019,6 @@ "type" : "boolean", "default" : false }, - "destab-with-sides": { - "title" : "incremental.restart.sided.destab-with-sides", - "description" : "TODO BROKEN", - "type" : "boolean", - "default" : true - }, "fuel": { "title": "incremental.restart.sided.fuel", "description": "Initial fuel for bounding transitive restarting, which uses one fuel each time when following side_fuel to restart. Zero fuel never restarts. Negative fuel doesn't bound (infinite fuel).", diff --git a/tests/incremental/11-restart/12-mutex-simple-access.json b/tests/incremental/11-restart/12-mutex-simple-access.json index d1a0187785..4fbaad990e 100644 --- a/tests/incremental/11-restart/12-mutex-simple-access.json +++ b/tests/incremental/11-restart/12-mutex-simple-access.json @@ -4,8 +4,9 @@ "sided": { "enabled": true, "only-access": true, - "destab-with-sides": false - } + "fuel": 1 + }, + "write-only": false } } } diff --git a/tests/incremental/11-restart/13-changed_start_state2.json b/tests/incremental/11-restart/13-changed_start_state2.json index 893cdedc4c..a116d4dfff 100644 --- a/tests/incremental/11-restart/13-changed_start_state2.json +++ b/tests/incremental/11-restart/13-changed_start_state2.json @@ -10,8 +10,7 @@ "restart": { "sided": { "enabled": true, - "only-access": true, - "destab-with-sides": true + "only-access": true } } } From 4ec572b77e3c497c47cb752aa2cf3c051052e85a Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 4 Aug 2022 14:14:35 +0300 Subject: [PATCH 398/402] Add option incremental.restart.sided.vars This simplifies the should_restart logic and makes the combination of both "only" options unrepresentable. --- src/solvers/td3.ml | 22 ++++++++++++------- src/util/options.schema.json | 17 +++++--------- .../11-restart/12-mutex-simple-access.json | 2 +- .../11-restart/13-changed_start_state2.json | 2 +- 4 files changed, 22 insertions(+), 21 deletions(-) diff --git a/src/solvers/td3.ml b/src/solvers/td3.ml index c3877dfae8..9728638345 100644 --- a/src/solvers/td3.ml +++ b/src/solvers/td3.ml @@ -103,8 +103,7 @@ module WP = let side_dep = data.side_dep in let side_infl = data.side_infl in let restart_sided = GobConfig.get_bool "incremental.restart.sided.enabled" in - let restart_only_globals = GobConfig.get_bool "incremental.restart.sided.only-global" in - let restart_only_access = GobConfig.get_bool "incremental.restart.sided.only-access" in + let restart_vars = GobConfig.get_string "incremental.restart.sided.vars" in let restart_wpoint = GobConfig.get_bool "solvers.td3.restart.wpoint.enabled" in let restart_once = GobConfig.get_bool "solvers.td3.restart.wpoint.once" in @@ -391,10 +390,14 @@ module WP = HM.remove side_dep x; let should_restart = - if restart_only_access then - S.Var.is_write_only x - else - (not restart_only_globals || Node.equal (S.Var.node x) (Function Cil.dummyFunDec)) && (not (S.Var.is_write_only x) || not restart_write_only) + match restart_write_only, S.Var.is_write_only x with + | true, true -> false (* prefer efficient write-only restarting during postsolving *) + | _, is_write_only -> + match restart_vars with + | "all" -> true + | "global" -> Node.equal (S.Var.node x) (Function Cil.dummyFunDec) (* non-function entry node *) + | "write-only" -> is_write_only + | _ -> assert false in if not (VS.is_empty w) && should_restart then ( @@ -634,10 +637,13 @@ module WP = destabilize x in + let should_restart_start = restart_sided && restart_vars <> "write-only" in (* assuming start vars are not write-only *) + (* TODO: should this distinguish non-global (function entry) and global (earlyglobs) start vars? *) + (* Call side on all globals and functions in the start variables to make sure that changes in the initializers are propagated. * This also destabilizes start functions if their start state changes because of globals that are neither in the start variables nor in the contexts *) List.iter (fun (v,d) -> - if restart_sided && not restart_only_access then ( + if should_restart_start then ( match GobList.assoc_eq_opt S.Var.equal v data.st with | Some old_d when not (S.Dom.equal old_d d) -> ignore (Pretty.printf "Destabilizing and restarting changed start var %a\n" S.Var.pretty_trace v); @@ -651,7 +657,7 @@ module WP = side v d ) st; - if restart_sided && not restart_only_access then ( + if should_restart_start then ( List.iter (fun (v, _) -> match GobList.assoc_eq_opt S.Var.equal v st with | None -> diff --git a/src/util/options.schema.json b/src/util/options.schema.json index aee7b045ff..90beacb057 100644 --- a/src/util/options.schema.json +++ b/src/util/options.schema.json @@ -1007,17 +1007,12 @@ "type": "boolean", "default": false }, - "only-global": { - "title": "incremental.restart.sided.only-global", - "description": "Restart only constraint system globals (not function entry nodes).", - "type": "boolean", - "default": false - }, - "only-access" : { - "title" : "incremental.restart.sided.only-access", - "description" : "Restart only write-only variables.", - "type" : "boolean", - "default" : false + "vars": { + "title": "incremental.restart.sided.vars", + "description": "Side-effected variables to restart. Globals are non-function entry nodes. Write-only is a subset of globals.", + "type": "string", + "enum": ["all", "global", "write-only"], + "default": "all" }, "fuel": { "title": "incremental.restart.sided.fuel", diff --git a/tests/incremental/11-restart/12-mutex-simple-access.json b/tests/incremental/11-restart/12-mutex-simple-access.json index 4fbaad990e..d038608da1 100644 --- a/tests/incremental/11-restart/12-mutex-simple-access.json +++ b/tests/incremental/11-restart/12-mutex-simple-access.json @@ -3,7 +3,7 @@ "restart": { "sided": { "enabled": true, - "only-access": true, + "vars": "write-only", "fuel": 1 }, "write-only": false diff --git a/tests/incremental/11-restart/13-changed_start_state2.json b/tests/incremental/11-restart/13-changed_start_state2.json index a116d4dfff..f2c44d4aae 100644 --- a/tests/incremental/11-restart/13-changed_start_state2.json +++ b/tests/incremental/11-restart/13-changed_start_state2.json @@ -10,7 +10,7 @@ "restart": { "sided": { "enabled": true, - "only-access": true + "vars": "write-only" } } } From aa563a65efa5426e5e109b21a916669748c5c5bc Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 10 Aug 2022 09:59:48 +0300 Subject: [PATCH 399/402] Add test annotations to 06-symbeq/38-chrony-name2ipaddress --- .../06-symbeq/38-chrony-name2ipaddress.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/tests/regression/06-symbeq/38-chrony-name2ipaddress.c b/tests/regression/06-symbeq/38-chrony-name2ipaddress.c index 05259683ee..3f5edd967a 100644 --- a/tests/regression/06-symbeq/38-chrony-name2ipaddress.c +++ b/tests/regression/06-symbeq/38-chrony-name2ipaddress.c @@ -85,7 +85,7 @@ DNS_Name2IPAddress(const char *name, IPAddr *ip_addrs, int max_addrs) max_addrs = MIN(max_addrs, DNS_MAX_ADDRESSES); for (i = 0; i < max_addrs; i++) - ip_addrs[i].family = IPADDR_UNSPEC; + ip_addrs[i].family = IPADDR_UNSPEC; // NORACE // #if 0 /* Avoid calling getaddrinfo() if the name is an IP address */ @@ -93,7 +93,7 @@ DNS_Name2IPAddress(const char *name, IPAddr *ip_addrs, int max_addrs) if (address_family != IPADDR_UNSPEC && ip.family != address_family) return DNS_Failure; if (max_addrs >= 1) - ip_addrs[0] = ip; + ip_addrs[0] = ip; // NORACE return DNS_Success; } @@ -128,8 +128,8 @@ DNS_Name2IPAddress(const char *name, IPAddr *ip_addrs, int max_addrs) case AF_INET: if (address_family != IPADDR_UNSPEC && address_family != IPADDR_INET4) continue; - ip_addrs[i].family = IPADDR_INET4; - ip_addrs[i].addr.in4 = ntohl(((struct sockaddr_in *)ai->ai_addr)->sin_addr.s_addr); + ip_addrs[i].family = IPADDR_INET4; // NORACE + ip_addrs[i].addr.in4 = ntohl(((struct sockaddr_in *)ai->ai_addr)->sin_addr.s_addr); // NORACE i++; break; #ifdef FEAT_IPV6 @@ -139,8 +139,8 @@ DNS_Name2IPAddress(const char *name, IPAddr *ip_addrs, int max_addrs) /* Don't return an address that would lose a scope ID */ if (((struct sockaddr_in6 *)ai->ai_addr)->sin6_scope_id != 0) continue; - ip_addrs[i].family = IPADDR_INET6; - memcpy(&ip_addrs[i].addr.in6, &((struct sockaddr_in6 *)ai->ai_addr)->sin6_addr.s6_addr, + ip_addrs[i].family = IPADDR_INET6; // NORACE + memcpy(&ip_addrs[i].addr.in6, &((struct sockaddr_in6 *)ai->ai_addr)->sin6_addr.s6_addr, // NORACE sizeof (ip_addrs->addr.in6)); i++; break; @@ -151,7 +151,7 @@ DNS_Name2IPAddress(const char *name, IPAddr *ip_addrs, int max_addrs) freeaddrinfo(res); // #endif - return !max_addrs || ip_addrs[0].family != IPADDR_UNSPEC ? DNS_Success : DNS_Failure; + return !max_addrs || ip_addrs[0].family != IPADDR_UNSPEC ? DNS_Success : DNS_Failure; // NORACE } struct DNS_Async_Instance { From af06a08a35d6f1e05f367fbeb64b0c65ad509e48 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 10 Aug 2022 10:07:53 +0300 Subject: [PATCH 400/402] Add test annotations to 51-threadjoins --- tests/regression/51-threadjoins/01-trivial.c | 5 +++++ tests/regression/51-threadjoins/02-other.c | 5 +++++ tests/regression/51-threadjoins/03-other-assume.c | 5 +++++ 3 files changed, 15 insertions(+) diff --git a/tests/regression/51-threadjoins/01-trivial.c b/tests/regression/51-threadjoins/01-trivial.c index 1eba60bf56..6ba9b6f47c 100644 --- a/tests/regression/51-threadjoins/01-trivial.c +++ b/tests/regression/51-threadjoins/01-trivial.c @@ -7,10 +7,12 @@ int h = 10; pthread_mutex_t A = PTHREAD_MUTEX_INITIALIZER; void *t_fun(void *arg) { + g++; // NORACE return NULL; } void *t_benign(void *arg) { + h++; // NORACE pthread_t id2; pthread_create(&id2, NULL, t_fun, NULL); pthread_join(id2, NULL); @@ -25,5 +27,8 @@ int main(void) { pthread_join(id2, NULL); // t_benign and t_fun should be in here + g++; // NORACE + h++; // NORACE + return 0; } diff --git a/tests/regression/51-threadjoins/02-other.c b/tests/regression/51-threadjoins/02-other.c index a4d0bb62f6..52200ad9bf 100644 --- a/tests/regression/51-threadjoins/02-other.c +++ b/tests/regression/51-threadjoins/02-other.c @@ -7,10 +7,12 @@ int h = 10; pthread_mutex_t A = PTHREAD_MUTEX_INITIALIZER; void *t_fun(void *arg) { + g++; // RACE! return NULL; } void *t_benign(void *arg) { + h++; // RACE! pthread_t id2; pthread_create(&id2, NULL, t_fun, NULL); pthread_join(id2, NULL); @@ -30,5 +32,8 @@ int main(void) { // should be empty + g++; // RACE! + h++; // RACE! + return 0; } diff --git a/tests/regression/51-threadjoins/03-other-assume.c b/tests/regression/51-threadjoins/03-other-assume.c index 71db72fcec..7827135e04 100644 --- a/tests/regression/51-threadjoins/03-other-assume.c +++ b/tests/regression/51-threadjoins/03-other-assume.c @@ -7,10 +7,12 @@ int h = 10; pthread_mutex_t A = PTHREAD_MUTEX_INITIALIZER; void *t_fun(void *arg) { + g++; // RACE! return NULL; } void *t_benign(void *arg) { + h++; // RACE! pthread_t id2; pthread_create(&id2, NULL, t_fun, NULL); __goblint_assume_join(id2, NULL); @@ -30,5 +32,8 @@ int main(void) { // t_benign and t_fun should be in here + g++; // NORACE + h++; // NORACE + return 0; } From 769e28da596f4e0815e12c715b70acdb8d21fb13 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 11 Aug 2022 12:42:12 +0300 Subject: [PATCH 401/402] Renumber incremental branch tests to avoid renumbering master branch tests --- .../01-restart_manual_simple.patch | 29 ---------------- .../02-read_write_global.patch | 34 ------------------- .../03-partial_contexts.patch | 28 --------------- .../01-unused_rename.c | 0 .../01-unused_rename.json | 0 .../04-var-rename/01-unused_rename.patch | 8 +++++ .../01-unused_rename.txt | 0 .../02-rename_and_shuffle.c | 0 .../02-rename_and_shuffle.json | 0 .../02-rename_and_shuffle.patch | 10 +++--- .../02-rename_and_shuffle.txt | 0 .../03-rename_with_usage.c | 0 .../03-rename_with_usage.json | 0 .../03-rename_with_usage.patch | 10 +++--- .../03-rename_with_usage.txt | 0 .../04-renamed_assert.c | 0 .../04-renamed_assert.json | 0 .../04-renamed_assert.patch | 4 +-- .../04-renamed_assert.txt | 0 .../05-renamed_param.c | 0 .../05-renamed_param.json | 0 .../04-var-rename/05-renamed_param.patch | 10 ++++++ .../05-renamed_param.txt | 0 .../06-renamed_param_usage_changed.c | 0 .../06-renamed_param_usage_changed.json | 0 .../06-renamed_param_usage_changed.patch | 6 ++-- .../06-renamed_param_usage_changed.txt | 0 .../08-2_incremental_runs.json | 0 .../08-2_incremental_runs_1.c | 0 .../08-2_incremental_runs_1.patch | 4 +-- .../08-2_incremental_runs_2.patch | 4 +-- .../09-2_ir_with_changes.json | 0 .../09-2_ir_with_changes_1.c | 0 .../09-2_ir_with_changes_1.patch | 4 +-- .../09-2_ir_with_changes_2.patch | 4 +-- .../05-var-rename/01-unused_rename.patch | 8 ----- .../05-var-rename/05-renamed_param.patch | 10 ------ .../01-restart_manual_simple.c | 0 .../01-restart_manual_simple.json | 0 .../01-restart_manual_simple.patch | 29 ++++++++++++++++ .../02-read_write_global.c | 0 .../02-read_write_global.json | 0 .../02-read_write_global.patch | 34 +++++++++++++++++++ .../03-partial_contexts.c | 0 .../03-partial_contexts.json | 0 .../03-partial_contexts.patch | 28 +++++++++++++++ .../{67-enums-minmax.c => 64-enums-minmax.c} | 0 ...-eval-on-write.c => 65-no-eval-on-write.c} | 0 ...te-multi.c => 66-no-eval-on-write-multi.c} | 0 ...xt-option.c => 67-no-int-context-option.c} | 0 ...ntext-option.c => 68-int-context-option.c} | 0 ...point.c => 69-ipmi-struct-blob-fixpoint.c} | 0 ...nknown-fp.c => 74-pcwd-deref-unknown-fp.c} | 0 53 files changed, 132 insertions(+), 132 deletions(-) delete mode 100644 tests/incremental/04-manual-restart/01-restart_manual_simple.patch delete mode 100644 tests/incremental/04-manual-restart/02-read_write_global.patch delete mode 100644 tests/incremental/04-manual-restart/03-partial_contexts.patch rename tests/incremental/{05-var-rename => 04-var-rename}/01-unused_rename.c (100%) rename tests/incremental/{05-var-rename => 04-var-rename}/01-unused_rename.json (100%) create mode 100644 tests/incremental/04-var-rename/01-unused_rename.patch rename tests/incremental/{05-var-rename => 04-var-rename}/01-unused_rename.txt (100%) rename tests/incremental/{05-var-rename => 04-var-rename}/02-rename_and_shuffle.c (100%) rename tests/incremental/{05-var-rename => 04-var-rename}/02-rename_and_shuffle.json (100%) rename tests/incremental/{05-var-rename => 04-var-rename}/02-rename_and_shuffle.patch (62%) rename tests/incremental/{05-var-rename => 04-var-rename}/02-rename_and_shuffle.txt (100%) rename tests/incremental/{05-var-rename => 04-var-rename}/03-rename_with_usage.c (100%) rename tests/incremental/{05-var-rename => 04-var-rename}/03-rename_with_usage.json (100%) rename tests/incremental/{05-var-rename => 04-var-rename}/03-rename_with_usage.patch (62%) rename tests/incremental/{05-var-rename => 04-var-rename}/03-rename_with_usage.txt (100%) rename tests/incremental/{05-var-rename => 04-var-rename}/04-renamed_assert.c (100%) rename tests/incremental/{05-var-rename => 04-var-rename}/04-renamed_assert.json (100%) rename tests/incremental/{05-var-rename => 04-var-rename}/04-renamed_assert.patch (64%) rename tests/incremental/{05-var-rename => 04-var-rename}/04-renamed_assert.txt (100%) rename tests/incremental/{05-var-rename => 04-var-rename}/05-renamed_param.c (100%) rename tests/incremental/{05-var-rename => 04-var-rename}/05-renamed_param.json (100%) create mode 100644 tests/incremental/04-var-rename/05-renamed_param.patch rename tests/incremental/{05-var-rename => 04-var-rename}/05-renamed_param.txt (100%) rename tests/incremental/{05-var-rename => 04-var-rename}/06-renamed_param_usage_changed.c (100%) rename tests/incremental/{05-var-rename => 04-var-rename}/06-renamed_param_usage_changed.json (100%) rename tests/incremental/{05-var-rename => 04-var-rename}/06-renamed_param_usage_changed.patch (55%) rename tests/incremental/{05-var-rename => 04-var-rename}/06-renamed_param_usage_changed.txt (100%) rename tests/incremental/{05-var-rename => 04-var-rename}/multiple_incremental_runs/08-2_incremental_runs.json (100%) rename tests/incremental/{05-var-rename => 04-var-rename}/multiple_incremental_runs/08-2_incremental_runs_1.c (100%) rename tests/incremental/{05-var-rename => 04-var-rename}/multiple_incremental_runs/08-2_incremental_runs_1.patch (67%) rename tests/incremental/{05-var-rename => 04-var-rename}/multiple_incremental_runs/08-2_incremental_runs_2.patch (67%) rename tests/incremental/{05-var-rename => 04-var-rename}/multiple_incremental_runs/09-2_ir_with_changes.json (100%) rename tests/incremental/{05-var-rename => 04-var-rename}/multiple_incremental_runs/09-2_ir_with_changes_1.c (100%) rename tests/incremental/{05-var-rename => 04-var-rename}/multiple_incremental_runs/09-2_ir_with_changes_1.patch (76%) rename tests/incremental/{05-var-rename => 04-var-rename}/multiple_incremental_runs/09-2_ir_with_changes_2.patch (61%) delete mode 100644 tests/incremental/05-var-rename/01-unused_rename.patch delete mode 100644 tests/incremental/05-var-rename/05-renamed_param.patch rename tests/incremental/{04-manual-restart => 14-manual-restart}/01-restart_manual_simple.c (100%) rename tests/incremental/{04-manual-restart => 14-manual-restart}/01-restart_manual_simple.json (100%) create mode 100644 tests/incremental/14-manual-restart/01-restart_manual_simple.patch rename tests/incremental/{04-manual-restart => 14-manual-restart}/02-read_write_global.c (100%) rename tests/incremental/{04-manual-restart => 14-manual-restart}/02-read_write_global.json (100%) create mode 100644 tests/incremental/14-manual-restart/02-read_write_global.patch rename tests/incremental/{04-manual-restart => 14-manual-restart}/03-partial_contexts.c (100%) rename tests/incremental/{04-manual-restart => 14-manual-restart}/03-partial_contexts.json (100%) create mode 100644 tests/incremental/14-manual-restart/03-partial_contexts.patch rename tests/regression/02-base/{67-enums-minmax.c => 64-enums-minmax.c} (100%) rename tests/regression/02-base/{68-no-eval-on-write.c => 65-no-eval-on-write.c} (100%) rename tests/regression/02-base/{69-no-eval-on-write-multi.c => 66-no-eval-on-write-multi.c} (100%) rename tests/regression/02-base/{64-no-int-context-option.c => 67-no-int-context-option.c} (100%) rename tests/regression/02-base/{65-int-context-option.c => 68-int-context-option.c} (100%) rename tests/regression/02-base/{74-ipmi-struct-blob-fixpoint.c => 69-ipmi-struct-blob-fixpoint.c} (100%) rename tests/regression/02-base/{99-pcwd-deref-unknown-fp.c => 74-pcwd-deref-unknown-fp.c} (100%) diff --git a/tests/incremental/04-manual-restart/01-restart_manual_simple.patch b/tests/incremental/04-manual-restart/01-restart_manual_simple.patch deleted file mode 100644 index 26def315a5..0000000000 --- a/tests/incremental/04-manual-restart/01-restart_manual_simple.patch +++ /dev/null @@ -1,29 +0,0 @@ -diff --git tests/incremental/04-manual-restart/01-restart_manual_simple.c tests/incremental/04-manual-restart/01-restart_manual_simple.c -index cbfb0ba70..aa83393ac 100644 ---- tests/incremental/04-manual-restart/01-restart_manual_simple.c -+++ tests/incremental/04-manual-restart/01-restart_manual_simple.c -@@ -1,9 +1,9 @@ - #include - --int g = 4; -+int g = 5; - - int main() { - int x = g; -- __goblint_check(x == 4); -+ __goblint_check(x == 4); //FAIL - return 0; - } -diff --git tests/incremental/04-manual-restart/01-restart_manual_simple.json tests/incremental/04-manual-restart/01-restart_manual_simple.json -index dbdb1d651..d66a6cf36 100644 ---- tests/incremental/04-manual-restart/01-restart_manual_simple.json -+++ tests/incremental/04-manual-restart/01-restart_manual_simple.json -@@ -7,7 +7,7 @@ - "sided": { - "enabled": false - }, -- "list": [] -+ "list": ["g"] - } - } - } diff --git a/tests/incremental/04-manual-restart/02-read_write_global.patch b/tests/incremental/04-manual-restart/02-read_write_global.patch deleted file mode 100644 index d193addf35..0000000000 --- a/tests/incremental/04-manual-restart/02-read_write_global.patch +++ /dev/null @@ -1,34 +0,0 @@ -diff --git tests/incremental/04-manual-restart/02-read_write_global.c tests/incremental/04-manual-restart/02-read_write_global.c -index 8a93caabe..521322dd0 100644 ---- tests/incremental/04-manual-restart/02-read_write_global.c -+++ tests/incremental/04-manual-restart/02-read_write_global.c -@@ -1,12 +1,12 @@ - int g = 0; - - void foo(){ -- g = 1; -+ g = 2; - } - - void bar(){ - int x = g; -- __goblint_check(x % 2 == 0); // UNKNOWN (imprecision caused by earlyglobs) -+ __goblint_check(x % 2 == 0); - } - - int main(){ -diff --git tests/incremental/04-manual-restart/02-read_write_global.json tests/incremental/04-manual-restart/02-read_write_global.json -index 33dd19da4..0820029df 100644 ---- tests/incremental/04-manual-restart/02-read_write_global.json -+++ tests/incremental/04-manual-restart/02-read_write_global.json -@@ -13,7 +13,9 @@ - "sided": { - "enabled": false - }, -- "list": [] -+ "list": [ -+ "g" -+ ] - } - } - } diff --git a/tests/incremental/04-manual-restart/03-partial_contexts.patch b/tests/incremental/04-manual-restart/03-partial_contexts.patch deleted file mode 100644 index a9fc69925c..0000000000 --- a/tests/incremental/04-manual-restart/03-partial_contexts.patch +++ /dev/null @@ -1,28 +0,0 @@ -diff --git tests/incremental/04-manual-restart/03-partial_contexts.c tests/incremental/04-manual-restart/03-partial_contexts.c -index a2a701673..d0b4d3efc 100644 ---- tests/incremental/04-manual-restart/03-partial_contexts.c -+++ tests/incremental/04-manual-restart/03-partial_contexts.c -@@ -4,7 +4,7 @@ int foo(int x){ - } - - int main(){ -- int x = 12; -+ int x = 13; - int y = foo(x); - __goblint_check(x == y); - return 0; -diff --git tests/incremental/04-manual-restart/03-partial_contexts.json tests/incremental/04-manual-restart/03-partial_contexts.json -index 96011c871..0a42408a0 100644 ---- tests/incremental/04-manual-restart/03-partial_contexts.json -+++ tests/incremental/04-manual-restart/03-partial_contexts.json -@@ -11,7 +11,9 @@ - "sided": { - "enabled": false - }, -- "list": [] -+ "list": [ -+ "foo" -+ ] - } - } - } diff --git a/tests/incremental/05-var-rename/01-unused_rename.c b/tests/incremental/04-var-rename/01-unused_rename.c similarity index 100% rename from tests/incremental/05-var-rename/01-unused_rename.c rename to tests/incremental/04-var-rename/01-unused_rename.c diff --git a/tests/incremental/05-var-rename/01-unused_rename.json b/tests/incremental/04-var-rename/01-unused_rename.json similarity index 100% rename from tests/incremental/05-var-rename/01-unused_rename.json rename to tests/incremental/04-var-rename/01-unused_rename.json diff --git a/tests/incremental/04-var-rename/01-unused_rename.patch b/tests/incremental/04-var-rename/01-unused_rename.patch new file mode 100644 index 0000000000..977470ad53 --- /dev/null +++ b/tests/incremental/04-var-rename/01-unused_rename.patch @@ -0,0 +1,8 @@ +--- tests/incremental/04-var-rename/01-unused_rename.c ++++ tests/incremental/04-var-rename/01-unused_rename.c +@@ -1,4 +1,4 @@ + int main() { +- int a = 0; ++ int b = 0; + return 0; + } diff --git a/tests/incremental/05-var-rename/01-unused_rename.txt b/tests/incremental/04-var-rename/01-unused_rename.txt similarity index 100% rename from tests/incremental/05-var-rename/01-unused_rename.txt rename to tests/incremental/04-var-rename/01-unused_rename.txt diff --git a/tests/incremental/05-var-rename/02-rename_and_shuffle.c b/tests/incremental/04-var-rename/02-rename_and_shuffle.c similarity index 100% rename from tests/incremental/05-var-rename/02-rename_and_shuffle.c rename to tests/incremental/04-var-rename/02-rename_and_shuffle.c diff --git a/tests/incremental/05-var-rename/02-rename_and_shuffle.json b/tests/incremental/04-var-rename/02-rename_and_shuffle.json similarity index 100% rename from tests/incremental/05-var-rename/02-rename_and_shuffle.json rename to tests/incremental/04-var-rename/02-rename_and_shuffle.json diff --git a/tests/incremental/05-var-rename/02-rename_and_shuffle.patch b/tests/incremental/04-var-rename/02-rename_and_shuffle.patch similarity index 62% rename from tests/incremental/05-var-rename/02-rename_and_shuffle.patch rename to tests/incremental/04-var-rename/02-rename_and_shuffle.patch index 2fffc7edfe..5c1dc4785e 100644 --- a/tests/incremental/05-var-rename/02-rename_and_shuffle.patch +++ b/tests/incremental/04-var-rename/02-rename_and_shuffle.patch @@ -1,15 +1,15 @@ ---- tests/incremental/05-var-rename/02-rename_and_shuffle.c -+++ tests/incremental/05-var-rename/02-rename_and_shuffle.c +--- tests/incremental/04-var-rename/02-rename_and_shuffle.c ++++ tests/incremental/04-var-rename/02-rename_and_shuffle.c @@ -2,10 +2,10 @@ - + //a is renamed to c, but the usage of a is replaced by b int main() { - int a = 0; + int c = 0; int b = 1; - + - printf("Print %d", a); + printf("Print %d", b); - + return 0; } diff --git a/tests/incremental/05-var-rename/02-rename_and_shuffle.txt b/tests/incremental/04-var-rename/02-rename_and_shuffle.txt similarity index 100% rename from tests/incremental/05-var-rename/02-rename_and_shuffle.txt rename to tests/incremental/04-var-rename/02-rename_and_shuffle.txt diff --git a/tests/incremental/05-var-rename/03-rename_with_usage.c b/tests/incremental/04-var-rename/03-rename_with_usage.c similarity index 100% rename from tests/incremental/05-var-rename/03-rename_with_usage.c rename to tests/incremental/04-var-rename/03-rename_with_usage.c diff --git a/tests/incremental/05-var-rename/03-rename_with_usage.json b/tests/incremental/04-var-rename/03-rename_with_usage.json similarity index 100% rename from tests/incremental/05-var-rename/03-rename_with_usage.json rename to tests/incremental/04-var-rename/03-rename_with_usage.json diff --git a/tests/incremental/05-var-rename/03-rename_with_usage.patch b/tests/incremental/04-var-rename/03-rename_with_usage.patch similarity index 62% rename from tests/incremental/05-var-rename/03-rename_with_usage.patch rename to tests/incremental/04-var-rename/03-rename_with_usage.patch index f250982797..26fb98b340 100644 --- a/tests/incremental/05-var-rename/03-rename_with_usage.patch +++ b/tests/incremental/04-var-rename/03-rename_with_usage.patch @@ -1,15 +1,15 @@ ---- tests/incremental/05-var-rename/03-rename_with_usage.c -+++ tests/incremental/05-var-rename/03-rename_with_usage.c +--- tests/incremental/04-var-rename/03-rename_with_usage.c ++++ tests/incremental/04-var-rename/03-rename_with_usage.c @@ -2,10 +2,10 @@ - + //a is renamed to c, but its usages stay the same int main() { - int a = 0; + int c = 0; int b = 1; - + - printf("Print %d", a); + printf("Print %d", c); - + return 0; } diff --git a/tests/incremental/05-var-rename/03-rename_with_usage.txt b/tests/incremental/04-var-rename/03-rename_with_usage.txt similarity index 100% rename from tests/incremental/05-var-rename/03-rename_with_usage.txt rename to tests/incremental/04-var-rename/03-rename_with_usage.txt diff --git a/tests/incremental/05-var-rename/04-renamed_assert.c b/tests/incremental/04-var-rename/04-renamed_assert.c similarity index 100% rename from tests/incremental/05-var-rename/04-renamed_assert.c rename to tests/incremental/04-var-rename/04-renamed_assert.c diff --git a/tests/incremental/05-var-rename/04-renamed_assert.json b/tests/incremental/04-var-rename/04-renamed_assert.json similarity index 100% rename from tests/incremental/05-var-rename/04-renamed_assert.json rename to tests/incremental/04-var-rename/04-renamed_assert.json diff --git a/tests/incremental/05-var-rename/04-renamed_assert.patch b/tests/incremental/04-var-rename/04-renamed_assert.patch similarity index 64% rename from tests/incremental/05-var-rename/04-renamed_assert.patch rename to tests/incremental/04-var-rename/04-renamed_assert.patch index 29988c4e8d..d7dfe6ae8e 100644 --- a/tests/incremental/05-var-rename/04-renamed_assert.patch +++ b/tests/incremental/04-var-rename/04-renamed_assert.patch @@ -1,5 +1,5 @@ ---- tests/incremental/05-var-rename/04-renamed_assert.c -+++ tests/incremental/05-var-rename/04-renamed_assert.c +--- tests/incremental/04-var-rename/04-renamed_assert.c ++++ tests/incremental/04-var-rename/04-renamed_assert.c @@ -1,7 +1,7 @@ int main() { - int myVar = 0; diff --git a/tests/incremental/05-var-rename/04-renamed_assert.txt b/tests/incremental/04-var-rename/04-renamed_assert.txt similarity index 100% rename from tests/incremental/05-var-rename/04-renamed_assert.txt rename to tests/incremental/04-var-rename/04-renamed_assert.txt diff --git a/tests/incremental/05-var-rename/05-renamed_param.c b/tests/incremental/04-var-rename/05-renamed_param.c similarity index 100% rename from tests/incremental/05-var-rename/05-renamed_param.c rename to tests/incremental/04-var-rename/05-renamed_param.c diff --git a/tests/incremental/05-var-rename/05-renamed_param.json b/tests/incremental/04-var-rename/05-renamed_param.json similarity index 100% rename from tests/incremental/05-var-rename/05-renamed_param.json rename to tests/incremental/04-var-rename/05-renamed_param.json diff --git a/tests/incremental/04-var-rename/05-renamed_param.patch b/tests/incremental/04-var-rename/05-renamed_param.patch new file mode 100644 index 0000000000..944566b05c --- /dev/null +++ b/tests/incremental/04-var-rename/05-renamed_param.patch @@ -0,0 +1,10 @@ +--- tests/incremental/04-var-rename/05-renamed_param.c ++++ tests/incremental/04-var-rename/05-renamed_param.c +@@ -1,5 +1,5 @@ +-void method(int a) { +- int c = a; ++void method(int b) { ++ int c = b; + } + + int main() { diff --git a/tests/incremental/05-var-rename/05-renamed_param.txt b/tests/incremental/04-var-rename/05-renamed_param.txt similarity index 100% rename from tests/incremental/05-var-rename/05-renamed_param.txt rename to tests/incremental/04-var-rename/05-renamed_param.txt diff --git a/tests/incremental/05-var-rename/06-renamed_param_usage_changed.c b/tests/incremental/04-var-rename/06-renamed_param_usage_changed.c similarity index 100% rename from tests/incremental/05-var-rename/06-renamed_param_usage_changed.c rename to tests/incremental/04-var-rename/06-renamed_param_usage_changed.c diff --git a/tests/incremental/05-var-rename/06-renamed_param_usage_changed.json b/tests/incremental/04-var-rename/06-renamed_param_usage_changed.json similarity index 100% rename from tests/incremental/05-var-rename/06-renamed_param_usage_changed.json rename to tests/incremental/04-var-rename/06-renamed_param_usage_changed.json diff --git a/tests/incremental/05-var-rename/06-renamed_param_usage_changed.patch b/tests/incremental/04-var-rename/06-renamed_param_usage_changed.patch similarity index 55% rename from tests/incremental/05-var-rename/06-renamed_param_usage_changed.patch rename to tests/incremental/04-var-rename/06-renamed_param_usage_changed.patch index 556e307775..a93e45c4c5 100644 --- a/tests/incremental/05-var-rename/06-renamed_param_usage_changed.patch +++ b/tests/incremental/04-var-rename/06-renamed_param_usage_changed.patch @@ -1,8 +1,8 @@ ---- tests/incremental/05-var-rename/06-renamed_param_usage_changed.c -+++ tests/incremental/05-var-rename/06-renamed_param_usage_changed.c +--- tests/incremental/04-var-rename/06-renamed_param_usage_changed.c ++++ tests/incremental/04-var-rename/06-renamed_param_usage_changed.c @@ -1,6 +1,6 @@ //This test should mark foo and main as changed - + -void foo(int a, int b) { +void foo(int b, int a) { int x = a; diff --git a/tests/incremental/05-var-rename/06-renamed_param_usage_changed.txt b/tests/incremental/04-var-rename/06-renamed_param_usage_changed.txt similarity index 100% rename from tests/incremental/05-var-rename/06-renamed_param_usage_changed.txt rename to tests/incremental/04-var-rename/06-renamed_param_usage_changed.txt diff --git a/tests/incremental/05-var-rename/multiple_incremental_runs/08-2_incremental_runs.json b/tests/incremental/04-var-rename/multiple_incremental_runs/08-2_incremental_runs.json similarity index 100% rename from tests/incremental/05-var-rename/multiple_incremental_runs/08-2_incremental_runs.json rename to tests/incremental/04-var-rename/multiple_incremental_runs/08-2_incremental_runs.json diff --git a/tests/incremental/05-var-rename/multiple_incremental_runs/08-2_incremental_runs_1.c b/tests/incremental/04-var-rename/multiple_incremental_runs/08-2_incremental_runs_1.c similarity index 100% rename from tests/incremental/05-var-rename/multiple_incremental_runs/08-2_incremental_runs_1.c rename to tests/incremental/04-var-rename/multiple_incremental_runs/08-2_incremental_runs_1.c diff --git a/tests/incremental/05-var-rename/multiple_incremental_runs/08-2_incremental_runs_1.patch b/tests/incremental/04-var-rename/multiple_incremental_runs/08-2_incremental_runs_1.patch similarity index 67% rename from tests/incremental/05-var-rename/multiple_incremental_runs/08-2_incremental_runs_1.patch rename to tests/incremental/04-var-rename/multiple_incremental_runs/08-2_incremental_runs_1.patch index 3fa5b8b853..1715a7c3d6 100644 --- a/tests/incremental/05-var-rename/multiple_incremental_runs/08-2_incremental_runs_1.patch +++ b/tests/incremental/04-var-rename/multiple_incremental_runs/08-2_incremental_runs_1.patch @@ -1,5 +1,5 @@ ---- tests/incremental/05-var-rename/08-2_incremental_runs_1.c -+++ tests/incremental/05-var-rename/08-2_incremental_runs_1.c +--- tests/incremental/04-var-rename/08-2_incremental_runs_1.c ++++ tests/incremental/04-var-rename/08-2_incremental_runs_1.c @@ -1,8 +1,8 @@ int main() { - int varFirstIteration = 0; diff --git a/tests/incremental/05-var-rename/multiple_incremental_runs/08-2_incremental_runs_2.patch b/tests/incremental/04-var-rename/multiple_incremental_runs/08-2_incremental_runs_2.patch similarity index 67% rename from tests/incremental/05-var-rename/multiple_incremental_runs/08-2_incremental_runs_2.patch rename to tests/incremental/04-var-rename/multiple_incremental_runs/08-2_incremental_runs_2.patch index 79472de576..a32e5a8c24 100644 --- a/tests/incremental/05-var-rename/multiple_incremental_runs/08-2_incremental_runs_2.patch +++ b/tests/incremental/04-var-rename/multiple_incremental_runs/08-2_incremental_runs_2.patch @@ -1,5 +1,5 @@ ---- tests/incremental/05-var-rename/08-2_incremental_runs_1.c -+++ tests/incremental/05-var-rename/08-2_incremental_runs_1.c +--- tests/incremental/04-var-rename/08-2_incremental_runs_1.c ++++ tests/incremental/04-var-rename/08-2_incremental_runs_1.c @@ -1,8 +1,8 @@ int main() { - int varSecondIteration = 0; diff --git a/tests/incremental/05-var-rename/multiple_incremental_runs/09-2_ir_with_changes.json b/tests/incremental/04-var-rename/multiple_incremental_runs/09-2_ir_with_changes.json similarity index 100% rename from tests/incremental/05-var-rename/multiple_incremental_runs/09-2_ir_with_changes.json rename to tests/incremental/04-var-rename/multiple_incremental_runs/09-2_ir_with_changes.json diff --git a/tests/incremental/05-var-rename/multiple_incremental_runs/09-2_ir_with_changes_1.c b/tests/incremental/04-var-rename/multiple_incremental_runs/09-2_ir_with_changes_1.c similarity index 100% rename from tests/incremental/05-var-rename/multiple_incremental_runs/09-2_ir_with_changes_1.c rename to tests/incremental/04-var-rename/multiple_incremental_runs/09-2_ir_with_changes_1.c diff --git a/tests/incremental/05-var-rename/multiple_incremental_runs/09-2_ir_with_changes_1.patch b/tests/incremental/04-var-rename/multiple_incremental_runs/09-2_ir_with_changes_1.patch similarity index 76% rename from tests/incremental/05-var-rename/multiple_incremental_runs/09-2_ir_with_changes_1.patch rename to tests/incremental/04-var-rename/multiple_incremental_runs/09-2_ir_with_changes_1.patch index 274ebfa768..d53031af00 100644 --- a/tests/incremental/05-var-rename/multiple_incremental_runs/09-2_ir_with_changes_1.patch +++ b/tests/incremental/04-var-rename/multiple_incremental_runs/09-2_ir_with_changes_1.patch @@ -1,5 +1,5 @@ ---- tests/incremental/05-var-rename/09-2_ir_with_changes_1.c -+++ tests/incremental/05-var-rename/09-2_ir_with_changes_1.c +--- tests/incremental/04-var-rename/09-2_ir_with_changes_1.c ++++ tests/incremental/04-var-rename/09-2_ir_with_changes_1.c @@ -1,13 +1,14 @@ void foo() { - int fooOne = 1; diff --git a/tests/incremental/05-var-rename/multiple_incremental_runs/09-2_ir_with_changes_2.patch b/tests/incremental/04-var-rename/multiple_incremental_runs/09-2_ir_with_changes_2.patch similarity index 61% rename from tests/incremental/05-var-rename/multiple_incremental_runs/09-2_ir_with_changes_2.patch rename to tests/incremental/04-var-rename/multiple_incremental_runs/09-2_ir_with_changes_2.patch index 5511bea85f..d0f8e07a50 100644 --- a/tests/incremental/05-var-rename/multiple_incremental_runs/09-2_ir_with_changes_2.patch +++ b/tests/incremental/04-var-rename/multiple_incremental_runs/09-2_ir_with_changes_2.patch @@ -1,5 +1,5 @@ ---- tests/incremental/05-var-rename/09-2_ir_with_changes_1.c -+++ tests/incremental/05-var-rename/09-2_ir_with_changes_1.c +--- tests/incremental/04-var-rename/09-2_ir_with_changes_1.c ++++ tests/incremental/04-var-rename/09-2_ir_with_changes_1.c @@ -1,7 +1,7 @@ void foo() { - int fooTwo = 1; diff --git a/tests/incremental/05-var-rename/01-unused_rename.patch b/tests/incremental/05-var-rename/01-unused_rename.patch deleted file mode 100644 index 7bfffe5a17..0000000000 --- a/tests/incremental/05-var-rename/01-unused_rename.patch +++ /dev/null @@ -1,8 +0,0 @@ ---- tests/incremental/05-var-rename/01-unused_rename.c -+++ tests/incremental/05-var-rename/01-unused_rename.c -@@ -1,4 +1,4 @@ - int main() { -- int a = 0; -+ int b = 0; - return 0; - } diff --git a/tests/incremental/05-var-rename/05-renamed_param.patch b/tests/incremental/05-var-rename/05-renamed_param.patch deleted file mode 100644 index 9c0ab193da..0000000000 --- a/tests/incremental/05-var-rename/05-renamed_param.patch +++ /dev/null @@ -1,10 +0,0 @@ ---- tests/incremental/05-var-rename/05-renamed_param.c -+++ tests/incremental/05-var-rename/05-renamed_param.c -@@ -1,5 +1,5 @@ --void method(int a) { -- int c = a; -+void method(int b) { -+ int c = b; - } - - int main() { diff --git a/tests/incremental/04-manual-restart/01-restart_manual_simple.c b/tests/incremental/14-manual-restart/01-restart_manual_simple.c similarity index 100% rename from tests/incremental/04-manual-restart/01-restart_manual_simple.c rename to tests/incremental/14-manual-restart/01-restart_manual_simple.c diff --git a/tests/incremental/04-manual-restart/01-restart_manual_simple.json b/tests/incremental/14-manual-restart/01-restart_manual_simple.json similarity index 100% rename from tests/incremental/04-manual-restart/01-restart_manual_simple.json rename to tests/incremental/14-manual-restart/01-restart_manual_simple.json diff --git a/tests/incremental/14-manual-restart/01-restart_manual_simple.patch b/tests/incremental/14-manual-restart/01-restart_manual_simple.patch new file mode 100644 index 0000000000..e5c345183f --- /dev/null +++ b/tests/incremental/14-manual-restart/01-restart_manual_simple.patch @@ -0,0 +1,29 @@ +diff --git tests/incremental/14-manual-restart/01-restart_manual_simple.c tests/incremental/14-manual-restart/01-restart_manual_simple.c +index cbfb0ba70..aa83393ac 100644 +--- tests/incremental/14-manual-restart/01-restart_manual_simple.c ++++ tests/incremental/14-manual-restart/01-restart_manual_simple.c +@@ -1,9 +1,9 @@ + #include + +-int g = 4; ++int g = 5; + + int main() { + int x = g; +- __goblint_check(x == 4); ++ __goblint_check(x == 4); //FAIL + return 0; + } +diff --git tests/incremental/14-manual-restart/01-restart_manual_simple.json tests/incremental/14-manual-restart/01-restart_manual_simple.json +index dbdb1d651..d66a6cf36 100644 +--- tests/incremental/14-manual-restart/01-restart_manual_simple.json ++++ tests/incremental/14-manual-restart/01-restart_manual_simple.json +@@ -7,7 +7,7 @@ + "sided": { + "enabled": false + }, +- "list": [] ++ "list": ["g"] + } + } + } diff --git a/tests/incremental/04-manual-restart/02-read_write_global.c b/tests/incremental/14-manual-restart/02-read_write_global.c similarity index 100% rename from tests/incremental/04-manual-restart/02-read_write_global.c rename to tests/incremental/14-manual-restart/02-read_write_global.c diff --git a/tests/incremental/04-manual-restart/02-read_write_global.json b/tests/incremental/14-manual-restart/02-read_write_global.json similarity index 100% rename from tests/incremental/04-manual-restart/02-read_write_global.json rename to tests/incremental/14-manual-restart/02-read_write_global.json diff --git a/tests/incremental/14-manual-restart/02-read_write_global.patch b/tests/incremental/14-manual-restart/02-read_write_global.patch new file mode 100644 index 0000000000..e6c81c87e7 --- /dev/null +++ b/tests/incremental/14-manual-restart/02-read_write_global.patch @@ -0,0 +1,34 @@ +diff --git tests/incremental/14-manual-restart/02-read_write_global.c tests/incremental/14-manual-restart/02-read_write_global.c +index 8a93caabe..521322dd0 100644 +--- tests/incremental/14-manual-restart/02-read_write_global.c ++++ tests/incremental/14-manual-restart/02-read_write_global.c +@@ -1,12 +1,12 @@ + int g = 0; + + void foo(){ +- g = 1; ++ g = 2; + } + + void bar(){ + int x = g; +- __goblint_check(x % 2 == 0); // UNKNOWN (imprecision caused by earlyglobs) ++ __goblint_check(x % 2 == 0); + } + + int main(){ +diff --git tests/incremental/14-manual-restart/02-read_write_global.json tests/incremental/14-manual-restart/02-read_write_global.json +index 33dd19da4..0820029df 100644 +--- tests/incremental/14-manual-restart/02-read_write_global.json ++++ tests/incremental/14-manual-restart/02-read_write_global.json +@@ -13,7 +13,9 @@ + "sided": { + "enabled": false + }, +- "list": [] ++ "list": [ ++ "g" ++ ] + } + } + } diff --git a/tests/incremental/04-manual-restart/03-partial_contexts.c b/tests/incremental/14-manual-restart/03-partial_contexts.c similarity index 100% rename from tests/incremental/04-manual-restart/03-partial_contexts.c rename to tests/incremental/14-manual-restart/03-partial_contexts.c diff --git a/tests/incremental/04-manual-restart/03-partial_contexts.json b/tests/incremental/14-manual-restart/03-partial_contexts.json similarity index 100% rename from tests/incremental/04-manual-restart/03-partial_contexts.json rename to tests/incremental/14-manual-restart/03-partial_contexts.json diff --git a/tests/incremental/14-manual-restart/03-partial_contexts.patch b/tests/incremental/14-manual-restart/03-partial_contexts.patch new file mode 100644 index 0000000000..7f3146e895 --- /dev/null +++ b/tests/incremental/14-manual-restart/03-partial_contexts.patch @@ -0,0 +1,28 @@ +diff --git tests/incremental/14-manual-restart/03-partial_contexts.c tests/incremental/14-manual-restart/03-partial_contexts.c +index a2a701673..d0b4d3efc 100644 +--- tests/incremental/14-manual-restart/03-partial_contexts.c ++++ tests/incremental/14-manual-restart/03-partial_contexts.c +@@ -4,7 +4,7 @@ int foo(int x){ + } + + int main(){ +- int x = 12; ++ int x = 13; + int y = foo(x); + __goblint_check(x == y); + return 0; +diff --git tests/incremental/14-manual-restart/03-partial_contexts.json tests/incremental/14-manual-restart/03-partial_contexts.json +index 96011c871..0a42408a0 100644 +--- tests/incremental/14-manual-restart/03-partial_contexts.json ++++ tests/incremental/14-manual-restart/03-partial_contexts.json +@@ -11,7 +11,9 @@ + "sided": { + "enabled": false + }, +- "list": [] ++ "list": [ ++ "foo" ++ ] + } + } + } diff --git a/tests/regression/02-base/67-enums-minmax.c b/tests/regression/02-base/64-enums-minmax.c similarity index 100% rename from tests/regression/02-base/67-enums-minmax.c rename to tests/regression/02-base/64-enums-minmax.c diff --git a/tests/regression/02-base/68-no-eval-on-write.c b/tests/regression/02-base/65-no-eval-on-write.c similarity index 100% rename from tests/regression/02-base/68-no-eval-on-write.c rename to tests/regression/02-base/65-no-eval-on-write.c diff --git a/tests/regression/02-base/69-no-eval-on-write-multi.c b/tests/regression/02-base/66-no-eval-on-write-multi.c similarity index 100% rename from tests/regression/02-base/69-no-eval-on-write-multi.c rename to tests/regression/02-base/66-no-eval-on-write-multi.c diff --git a/tests/regression/02-base/64-no-int-context-option.c b/tests/regression/02-base/67-no-int-context-option.c similarity index 100% rename from tests/regression/02-base/64-no-int-context-option.c rename to tests/regression/02-base/67-no-int-context-option.c diff --git a/tests/regression/02-base/65-int-context-option.c b/tests/regression/02-base/68-int-context-option.c similarity index 100% rename from tests/regression/02-base/65-int-context-option.c rename to tests/regression/02-base/68-int-context-option.c diff --git a/tests/regression/02-base/74-ipmi-struct-blob-fixpoint.c b/tests/regression/02-base/69-ipmi-struct-blob-fixpoint.c similarity index 100% rename from tests/regression/02-base/74-ipmi-struct-blob-fixpoint.c rename to tests/regression/02-base/69-ipmi-struct-blob-fixpoint.c diff --git a/tests/regression/02-base/99-pcwd-deref-unknown-fp.c b/tests/regression/02-base/74-pcwd-deref-unknown-fp.c similarity index 100% rename from tests/regression/02-base/99-pcwd-deref-unknown-fp.c rename to tests/regression/02-base/74-pcwd-deref-unknown-fp.c From 26aa6b7ab0ec6058e1f718f4799d2d1cb669b784 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 11 Aug 2022 13:01:09 +0300 Subject: [PATCH 402/402] Restore most recent g2html --- g2html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/g2html b/g2html index 49a7a8d21c..c46288a560 160000 --- a/g2html +++ b/g2html @@ -1 +1 @@ -Subproject commit 49a7a8d21c6741d57d35ee5ba175c8ff32a4d0b9 +Subproject commit c46288a56047aac6c351292e8f4a286d347eed37