From 2fb5390dc0085864da2f1b426e1b5ba2cd97b800 Mon Sep 17 00:00:00 2001 From: Michael Schwarz Date: Tue, 24 Dec 2024 18:41:47 +0100 Subject: [PATCH 01/68] First steps --- src/analyses/pthreadBarriers.ml | 43 +++++++++++++++++++++++++ src/util/library/libraryDesc.ml | 2 ++ src/util/library/libraryFunctions.ml | 2 ++ tests/regression/82-barrier/01-simple.c | 34 +++++++++++++++++++ 4 files changed, 81 insertions(+) create mode 100644 src/analyses/pthreadBarriers.ml create mode 100644 tests/regression/82-barrier/01-simple.c diff --git a/src/analyses/pthreadBarriers.ml b/src/analyses/pthreadBarriers.ml new file mode 100644 index 0000000000..c414175dc6 --- /dev/null +++ b/src/analyses/pthreadBarriers.ml @@ -0,0 +1,43 @@ +(** Must have waited barriers for Pthread barriers ([pthreadBarriers]). *) + +open GoblintCil +open Analyses +module LF = LibraryFunctions + +module Spec = +struct + module Barriers = SetDomain.ToppedSet (ValueDomain.Addr) (struct let topname = "All barriers" end) + module MustBarriers = Lattice.Reverse (Barriers) + + include Analyses.IdentitySpec + module V = VarinfoV + + let name () = "pthreadBarriers" + module D = Lattice.Prod (Barriers) (MustBarriers) + + include Analyses.ValueContexts(D) + + let possible_vinfos (a: Queries.ask) barrier = + Queries.AD.to_var_may (a.f (Queries.MayPointTo barrier)) + + let special man (lval: lval option) (f:varinfo) (arglist:exp list) : D.t = + let desc = LF.find f in + match desc.special arglist with + | BarrierWait barrier -> + let may, must = man.local in + let barriers = possible_vinfos (Analyses.ask_of_man man) barrier in + let may = List.fold_left (fun may a -> Barriers.add (ValueDomain.Addr.of_var a) may) may barriers in + let must = match barriers with + | [a] -> Barriers.add (ValueDomain.Addr.of_var a) must + | _ -> must + in + (may, must) + | _ -> man.local + + let startstate v = (Barriers.empty (), Barriers.empty ()) + let threadenter man ~multiple lval f args = [man.local] + let exitstate v = (Barriers.empty (), Barriers.empty ()) +end + +let _ = + MCP.register_analysis (module Spec : MCPSpec) diff --git a/src/util/library/libraryDesc.ml b/src/util/library/libraryDesc.ml index 6f34de1864..2da79dcc20 100644 --- a/src/util/library/libraryDesc.ml +++ b/src/util/library/libraryDesc.ml @@ -69,6 +69,8 @@ type special = | SemDestroy of Cil.exp | Wait of { cond: Cil.exp; mutex: Cil.exp; } | TimedWait of { cond: Cil.exp; mutex: Cil.exp; abstime: Cil.exp; (** Unused *) } + | BarrierWait of Cil.exp + | BarrierInit of { barrier: Cil.exp; count: Cil.exp; } | Math of { fun_args: math; } | Memset of { dest: Cil.exp; ch: Cil.exp; count: Cil.exp; } | Bzero of { dest: Cil.exp; count: Cil.exp; } diff --git a/src/util/library/libraryFunctions.ml b/src/util/library/libraryFunctions.ml index 6643b58eef..ab7d682483 100644 --- a/src/util/library/libraryFunctions.ml +++ b/src/util/library/libraryFunctions.ml @@ -520,6 +520,8 @@ let pthread_descs_list: (string * LibraryDesc.t) list = LibraryDsl.[ ("pthread_getspecific", unknown ~attrs:[InvalidateGlobals] [drop "key" []]); ("pthread_key_create", unknown [drop "key" [w]; drop "destructor" [s]]); ("pthread_key_delete", unknown [drop "key" [f]]); + ("pthread_barrier_init", special [__ "barrier" []; __ "attr" []; __ "count" []] @@ fun barrier attr count -> BarrierInit {barrier; count}); + ("pthread_barrier_wait", special [__ "barrier" []] @@ fun barrier -> BarrierWait barrier); ("pthread_cancel", unknown [drop "thread" []]); ("pthread_testcancel", unknown []); ("pthread_setcancelstate", unknown [drop "state" []; drop "oldstate" [w]]); diff --git a/tests/regression/82-barrier/01-simple.c b/tests/regression/82-barrier/01-simple.c new file mode 100644 index 0000000000..69307e252f --- /dev/null +++ b/tests/regression/82-barrier/01-simple.c @@ -0,0 +1,34 @@ +// PARAM: --set ana.activated[+] 'pthreadBarriers' +#include +#include +#include + +int g; + +pthread_barrier_t barrier; + +void* f1(void* ptr) { + return NULL; +} + +void* f2(void* ptr) { + return NULL; +} + +int main(int argc, char const *argv[]) +{ + pthread_barrier_init(&barrier, NULL, 2); + pthread_barrier_wait(&barrier); + + pthread_t t1; + pthread_t t2; + + pthread_create(&t1,NULL,f1,NULL); + sleep(1); + pthread_create(&t2,NULL,f2,NULL); + + pthread_join(t1, NULL); + pthread_join(t2, NULL); + + return 0; +} From 29a39005efa967d9f5c214ac72db3eb02ffe67a5 Mon Sep 17 00:00:00 2001 From: Michael Schwarz Date: Tue, 24 Dec 2024 18:56:39 +0100 Subject: [PATCH 02/68] Record capacity --- src/analyses/pthreadBarriers.ml | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/src/analyses/pthreadBarriers.ml b/src/analyses/pthreadBarriers.ml index c414175dc6..ad5759c458 100644 --- a/src/analyses/pthreadBarriers.ml +++ b/src/analyses/pthreadBarriers.ml @@ -6,12 +6,22 @@ module LF = LibraryFunctions module Spec = struct - module Barriers = SetDomain.ToppedSet (ValueDomain.Addr) (struct let topname = "All barriers" end) - module MustBarriers = Lattice.Reverse (Barriers) + module Barriers = struct + include SetDomain.ToppedSet (ValueDomain.Addr) (struct let topname = "All barriers" end) + let name () = "mayBarriers" + end + + module MustBarriers = struct + include Lattice.Reverse (Barriers) + let name () = "mustBarriers" + end include Analyses.IdentitySpec module V = VarinfoV + module Waiters = SetDomain.ToppedSet (MHP) (struct let topname = "All MHP" end) + module G = Lattice.Prod (Queries.ID) (Waiters) + let name () = "pthreadBarriers" module D = Lattice.Prod (Barriers) (MustBarriers) @@ -32,6 +42,12 @@ struct | _ -> must in (may, must) + | BarrierInit { barrier; count } -> + let count = man.ask (Queries.EvalInt count) in + let publish_one b = man.sideg b (count, Waiters.bot ()) in + let barriers = possible_vinfos (Analyses.ask_of_man man) barrier in + List.iter publish_one barriers; + man.local | _ -> man.local let startstate v = (Barriers.empty (), Barriers.empty ()) From 60c1d72fff598c29f06fd99e1b38e27e3098da1e Mon Sep 17 00:00:00 2001 From: Michael Schwarz Date: Tue, 24 Dec 2024 19:41:24 +0100 Subject: [PATCH 03/68] Add first checks --- src/analyses/pthreadBarriers.ml | 39 ++++++++++++++++++---- tests/regression/82-barrier/01-simple.c | 26 ++++++--------- tests/regression/82-barrier/02-more.c | 43 +++++++++++++++++++++++++ 3 files changed, 84 insertions(+), 24 deletions(-) create mode 100644 tests/regression/82-barrier/02-more.c diff --git a/src/analyses/pthreadBarriers.ml b/src/analyses/pthreadBarriers.ml index ad5759c458..93f6638fd1 100644 --- a/src/analyses/pthreadBarriers.ml +++ b/src/analyses/pthreadBarriers.ml @@ -16,11 +16,14 @@ struct let name () = "mustBarriers" end + module Capacity = Queries.ID + include Analyses.IdentitySpec module V = VarinfoV - module Waiters = SetDomain.ToppedSet (MHP) (struct let topname = "All MHP" end) - module G = Lattice.Prod (Queries.ID) (Waiters) + module TID = ThreadIdDomain.Thread + module Waiters = SetDomain.ToppedSet (TID) (struct let topname = "All MHP" end) + module G = Lattice.Prod (Capacity) (Waiters) let name () = "pthreadBarriers" module D = Lattice.Prod (Barriers) (MustBarriers) @@ -34,13 +37,35 @@ struct let desc = LF.find f in match desc.special arglist with | BarrierWait barrier -> + let ask = Analyses.ask_of_man man in let may, must = man.local in - let barriers = possible_vinfos (Analyses.ask_of_man man) barrier in - let may = List.fold_left (fun may a -> Barriers.add (ValueDomain.Addr.of_var a) may) may barriers in - let must = match barriers with - | [a] -> Barriers.add (ValueDomain.Addr.of_var a) must - | _ -> must + let barriers = possible_vinfos ask barrier in + let tid = match ThreadId.get_current ask with + | `Lifted tid -> Waiters.singleton tid + | _ -> Waiters.top () + in + let handle_one b = + man.sideg b (Capacity.bot (), tid); + let addr = ValueDomain.Addr.of_var b in + let (capacity, waiters) = man.global b in + let relevant_waiters = Waiters.filter (fun tid -> true) waiters in + let may_run = + if Waiters.exists (fun tid -> not @@ TID.is_unique tid) relevant_waiters then + true + else + let count = Waiters.cardinal relevant_waiters in + match capacity with + | `Lifted c -> + Z.geq (Z.of_int count) (BatOption.default Z.zero (Capacity.I.minimal c)) + | _ -> true + in + if may_run then + (Barriers.add addr may, Barriers.add addr must) + else + D.bot () in + let (may, must) = List.fold_left (fun acc b-> D.join acc (handle_one b)) (D.bot ()) barriers in + if Barriers.is_empty may then raise Analyses.Deadcode; (may, must) | BarrierInit { barrier; count } -> let count = man.ask (Queries.EvalInt count) in diff --git a/tests/regression/82-barrier/01-simple.c b/tests/regression/82-barrier/01-simple.c index 69307e252f..696e433962 100644 --- a/tests/regression/82-barrier/01-simple.c +++ b/tests/regression/82-barrier/01-simple.c @@ -7,28 +7,20 @@ int g; pthread_barrier_t barrier; -void* f1(void* ptr) { - return NULL; -} - -void* f2(void* ptr) { - return NULL; -} int main(int argc, char const *argv[]) { + int top; + int i = 0; + pthread_barrier_init(&barrier, NULL, 2); - pthread_barrier_wait(&barrier); - pthread_t t1; - pthread_t t2; - - pthread_create(&t1,NULL,f1,NULL); - sleep(1); - pthread_create(&t2,NULL,f2,NULL); - - pthread_join(t1, NULL); - pthread_join(t2, NULL); + if(top) { + pthread_barrier_wait(&barrier); + // Unreachable + i = 1; + } + __goblint_check(i == 0); return 0; } diff --git a/tests/regression/82-barrier/02-more.c b/tests/regression/82-barrier/02-more.c new file mode 100644 index 0000000000..9ff084be11 --- /dev/null +++ b/tests/regression/82-barrier/02-more.c @@ -0,0 +1,43 @@ +// PARAM: --set ana.activated[+] 'pthreadBarriers' +#include +#include +#include + +int g; + +pthread_barrier_t barrier; + +void* f2(void* ptr) { + return NULL; +} + +void* f1(void* ptr) { + pthread_barrier_wait(&barrier); + + pthread_t t2; + pthread_create(&t2,NULL,f2,NULL); + + return NULL; +} + +int main(int argc, char const *argv[]) +{ + int top; + int i = 0; + + pthread_barrier_init(&barrier, NULL, 3); + + if(top) { + pthread_barrier_wait(&barrier); + // Unreachable + i = 1; + } + + __goblint_check(i == 0); + pthread_t t1; + + + pthread_create(&t1,NULL,f1,NULL); + + return 0; +} From 041e544c39fbbdcb027cd698fa938f0cba07fc52 Mon Sep 17 00:00:00 2001 From: Michael Schwarz Date: Tue, 24 Dec 2024 20:04:16 +0100 Subject: [PATCH 04/68] Use MHP information --- src/analyses/pthreadBarriers.ml | 13 +++++-------- src/cdomains/mHP.ml | 5 +++++ tests/regression/82-barrier/02-more.c | 12 +++++++++--- 3 files changed, 19 insertions(+), 11 deletions(-) diff --git a/src/analyses/pthreadBarriers.ml b/src/analyses/pthreadBarriers.ml index 93f6638fd1..03d3620f5c 100644 --- a/src/analyses/pthreadBarriers.ml +++ b/src/analyses/pthreadBarriers.ml @@ -22,7 +22,7 @@ struct module V = VarinfoV module TID = ThreadIdDomain.Thread - module Waiters = SetDomain.ToppedSet (TID) (struct let topname = "All MHP" end) + module Waiters = SetDomain.ToppedSet (MHP) (struct let topname = "All MHP" end) module G = Lattice.Prod (Capacity) (Waiters) let name () = "pthreadBarriers" @@ -40,17 +40,14 @@ struct let ask = Analyses.ask_of_man man in let may, must = man.local in let barriers = possible_vinfos ask barrier in - let tid = match ThreadId.get_current ask with - | `Lifted tid -> Waiters.singleton tid - | _ -> Waiters.top () - in + let mhp = MHP.current ask in let handle_one b = - man.sideg b (Capacity.bot (), tid); + man.sideg b (Capacity.bot (), Waiters.singleton mhp); let addr = ValueDomain.Addr.of_var b in let (capacity, waiters) = man.global b in - let relevant_waiters = Waiters.filter (fun tid -> true) waiters in + let relevant_waiters = Waiters.filter (fun other -> MHP.may_happen_in_parallel mhp other) waiters in let may_run = - if Waiters.exists (fun tid -> not @@ TID.is_unique tid) relevant_waiters then + if Waiters.exists MHP.may_be_non_unique_thread relevant_waiters then true else let count = Waiters.cardinal relevant_waiters in diff --git a/src/cdomains/mHP.ml b/src/cdomains/mHP.ml index 433486d4e0..13bf81819b 100644 --- a/src/cdomains/mHP.ml +++ b/src/cdomains/mHP.ml @@ -92,3 +92,8 @@ let may_happen_in_parallel one two = else true | _ -> true + +let may_be_non_unique_thread mhp = + match mhp.tid with + | `Lifted tid -> not (TID.is_unique tid) + | _ -> true \ No newline at end of file diff --git a/tests/regression/82-barrier/02-more.c b/tests/regression/82-barrier/02-more.c index 9ff084be11..2b50b3ad06 100644 --- a/tests/regression/82-barrier/02-more.c +++ b/tests/regression/82-barrier/02-more.c @@ -8,12 +8,14 @@ int g; pthread_barrier_t barrier; void* f2(void* ptr) { + pthread_barrier_wait(&barrier); return NULL; } void* f1(void* ptr) { pthread_barrier_wait(&barrier); + // This is past the barrier, so it will not be reached pthread_t t2; pthread_create(&t2,NULL,f2,NULL); @@ -26,6 +28,9 @@ int main(int argc, char const *argv[]) int i = 0; pthread_barrier_init(&barrier, NULL, 3); + + pthread_t t1; + pthread_create(&t1,NULL,f1,NULL); if(top) { pthread_barrier_wait(&barrier); @@ -33,11 +38,12 @@ int main(int argc, char const *argv[]) i = 1; } - __goblint_check(i == 0); - pthread_t t1; + // Created too late to have any effect + pthread_t t2; + pthread_create(&t2,NULL,f1,NULL); + __goblint_check(i == 0); - pthread_create(&t1,NULL,f1,NULL); return 0; } From db320aed96ce7e7d413a2171e0f1e172953b98dd Mon Sep 17 00:00:00 2001 From: Michael Schwarz Date: Tue, 24 Dec 2024 21:32:46 +0100 Subject: [PATCH 05/68] More involved MHP check --- src/analyses/pthreadBarriers.ml | 21 +++++++- tests/regression/82-barrier/02-more.c | 4 -- tests/regression/82-barrier/03-problem.c | 36 ++++++++++++++ tests/regression/82-barrier/04-challenge.c | 49 +++++++++++++++++++ .../regression/82-barrier/05-mhp-not-enough.c | 45 +++++++++++++++++ 5 files changed, 150 insertions(+), 5 deletions(-) create mode 100644 tests/regression/82-barrier/03-problem.c create mode 100644 tests/regression/82-barrier/04-challenge.c create mode 100644 tests/regression/82-barrier/05-mhp-not-enough.c diff --git a/src/analyses/pthreadBarriers.ml b/src/analyses/pthreadBarriers.ml index 03d3620f5c..a02c3332f4 100644 --- a/src/analyses/pthreadBarriers.ml +++ b/src/analyses/pthreadBarriers.ml @@ -53,7 +53,26 @@ struct let count = Waiters.cardinal relevant_waiters in match capacity with | `Lifted c -> - Z.geq (Z.of_int count) (BatOption.default Z.zero (Capacity.I.minimal c)) + (* Add 1 as the thread calling wait at the moment will not be MHP with itself *) + let min_cap = (BatOption.default Z.zero (Capacity.I.minimal c)) in + if Z.leq min_cap Z.one then + true + else if min_cap = Z.of_int 2 && count = 1 then + true + else if Z.geq (Z.of_int (count + 1)) min_cap then + (* This is quite a cute problem: Do (min_cap-1) elements exist in the set such that + MHP is pairwise true? This solution is a sledgehammer, there should be something much + better algorithmically (beyond just laziness) *) + let waiters = Waiters.elements relevant_waiters in + let min_cap = Z.to_int min_cap in + let lists = List.init (min_cap - 1) (fun _ -> waiters) in + let candidates = BatList.n_cartesian_product lists in + List.exists (fun candidate -> + let pairwise = BatList.cartesian_product candidate candidate in + List.for_all (fun (a,b) -> MHP.may_happen_in_parallel a b) pairwise + ) candidates + else + false | _ -> true in if may_run then diff --git a/tests/regression/82-barrier/02-more.c b/tests/regression/82-barrier/02-more.c index 2b50b3ad06..cdabe740ea 100644 --- a/tests/regression/82-barrier/02-more.c +++ b/tests/regression/82-barrier/02-more.c @@ -38,10 +38,6 @@ int main(int argc, char const *argv[]) i = 1; } - // Created too late to have any effect - pthread_t t2; - pthread_create(&t2,NULL,f1,NULL); - __goblint_check(i == 0); diff --git a/tests/regression/82-barrier/03-problem.c b/tests/regression/82-barrier/03-problem.c new file mode 100644 index 0000000000..d75245ccdd --- /dev/null +++ b/tests/regression/82-barrier/03-problem.c @@ -0,0 +1,36 @@ +// PARAM: --set ana.activated[+] 'pthreadBarriers' +#include +#include +#include + +int g; + +pthread_barrier_t barrier; + + +void* f1(void* ptr) { + pthread_barrier_wait(&barrier); + return NULL; +} + +int main(int argc, char const *argv[]) +{ + int top; + int i = 0; + + pthread_barrier_init(&barrier, NULL, 2); + + pthread_t t1; + pthread_create(&t1,NULL,f1,NULL); + + if(top) { + pthread_barrier_wait(&barrier); + // Live! + i = 1; + } + + __goblint_check(i == 0); //UNKNOWN! + + + return 0; +} diff --git a/tests/regression/82-barrier/04-challenge.c b/tests/regression/82-barrier/04-challenge.c new file mode 100644 index 0000000000..2b50b3ad06 --- /dev/null +++ b/tests/regression/82-barrier/04-challenge.c @@ -0,0 +1,49 @@ +// PARAM: --set ana.activated[+] 'pthreadBarriers' +#include +#include +#include + +int g; + +pthread_barrier_t barrier; + +void* f2(void* ptr) { + pthread_barrier_wait(&barrier); + return NULL; +} + +void* f1(void* ptr) { + pthread_barrier_wait(&barrier); + + // This is past the barrier, so it will not be reached + pthread_t t2; + pthread_create(&t2,NULL,f2,NULL); + + return NULL; +} + +int main(int argc, char const *argv[]) +{ + int top; + int i = 0; + + pthread_barrier_init(&barrier, NULL, 3); + + pthread_t t1; + pthread_create(&t1,NULL,f1,NULL); + + if(top) { + pthread_barrier_wait(&barrier); + // Unreachable + i = 1; + } + + // Created too late to have any effect + pthread_t t2; + pthread_create(&t2,NULL,f1,NULL); + + __goblint_check(i == 0); + + + return 0; +} diff --git a/tests/regression/82-barrier/05-mhp-not-enough.c b/tests/regression/82-barrier/05-mhp-not-enough.c new file mode 100644 index 0000000000..4fcb460d61 --- /dev/null +++ b/tests/regression/82-barrier/05-mhp-not-enough.c @@ -0,0 +1,45 @@ +// PARAM: --set ana.activated[+] 'pthreadBarriers' +#include +#include +#include + +int g; + +pthread_barrier_t barrier; + + +void* f1(void* ptr) { + pthread_barrier_wait(&barrier); + + // This should not be reached as either main calls wait or the other thread is created + // -> In the concrete, there never are three threads calling wait + + return NULL; +} + +int main(int argc, char const *argv[]) +{ + int top; + int top2; + int i = 0; + + pthread_barrier_init(&barrier, NULL, 3); + + pthread_t t1; + pthread_create(&t1,NULL,f1,NULL); + + if(top) { + pthread_barrier_wait(&barrier); + // Unreachable + i = 1; + } else { + pthread_t t2; + pthread_create(&t2,NULL,f1,NULL); + } + + + __goblint_check(i == 0); + + + return 0; +} From 8b2ede3fe3d21e6c6ad84ffb6575b021215764dd Mon Sep 17 00:00:00 2001 From: Michael Schwarz Date: Tue, 24 Dec 2024 21:33:29 +0100 Subject: [PATCH 06/68] Rm spurious variable --- tests/regression/82-barrier/05-mhp-not-enough.c | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/regression/82-barrier/05-mhp-not-enough.c b/tests/regression/82-barrier/05-mhp-not-enough.c index 4fcb460d61..c627a4ff04 100644 --- a/tests/regression/82-barrier/05-mhp-not-enough.c +++ b/tests/regression/82-barrier/05-mhp-not-enough.c @@ -20,7 +20,6 @@ void* f1(void* ptr) { int main(int argc, char const *argv[]) { int top; - int top2; int i = 0; pthread_barrier_init(&barrier, NULL, 3); From f418b00dc200772d4fa0e16ead0e181602792afd Mon Sep 17 00:00:00 2001 From: Michael Schwarz Date: Tue, 24 Dec 2024 21:35:11 +0100 Subject: [PATCH 07/68] Document pthread barriers --- src/goblint_lib.ml | 1 + 1 file changed, 1 insertion(+) diff --git a/src/goblint_lib.ml b/src/goblint_lib.ml index 415fb21605..b63d804a2f 100644 --- a/src/goblint_lib.ml +++ b/src/goblint_lib.ml @@ -129,6 +129,7 @@ module BasePriv = BasePriv module RelationPriv = RelationPriv module ThreadEscape = ThreadEscape module PthreadSignals = PthreadSignals +module PthreadBarriers = PthreadBarriers module ExtractPthread = ExtractPthread (** {2 Longjmp} From 93b7f0c766d00919cba7cba8be0ce63c8e5572d7 Mon Sep 17 00:00:00 2001 From: Michael Schwarz Date: Wed, 25 Dec 2024 16:00:13 +0100 Subject: [PATCH 08/68] Add `NOMAC` option --- .github/workflows/coverage.yml | 3 +++ .github/workflows/docs.yml | 3 +++ .github/workflows/locked.yml | 9 +++++++++ .github/workflows/unlocked.yml | 6 ++++++ make.sh | 1 + scripts/update_suite.rb | 4 ++++ tests/regression/82-barrier/01-simple.c | 2 +- tests/regression/82-barrier/02-more.c | 2 +- tests/regression/82-barrier/03-problem.c | 2 +- tests/regression/82-barrier/04-challenge.c | 2 +- tests/regression/82-barrier/05-mhp-not-enough.c | 2 +- 11 files changed, 31 insertions(+), 5 deletions(-) diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml index fd2c55b84e..3f924869fc 100644 --- a/.github/workflows/coverage.yml +++ b/.github/workflows/coverage.yml @@ -46,6 +46,9 @@ jobs: - name: Install dependencies run: opam install . --deps-only --locked --with-test + - name: Install os gem for operating system detection + run: sudo gem install os + - name: Install coverage dependencies run: opam install bisect_ppx diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index 0ada04e369..1a6d17fab4 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -46,6 +46,9 @@ jobs: - name: Install dependencies run: opam install . --deps-only --locked --with-doc + - name: Install os gem for operating system detection + run: sudo gem install os + - name: Build API docs run: opam exec -- dune build @doc diff --git a/.github/workflows/locked.yml b/.github/workflows/locked.yml index 16655bfdc7..8205d4ef34 100644 --- a/.github/workflows/locked.yml +++ b/.github/workflows/locked.yml @@ -48,6 +48,9 @@ jobs: - name: Install dependencies run: opam install . --deps-only --locked --with-test + - name: Install os gem for operating system detection + run: sudo gem install os + - name: Build run: ./make.sh nat @@ -100,6 +103,9 @@ jobs: - name: Install dependencies run: opam install . --deps-only --locked --with-test + - name: Install os gem for operating system detection + run: sudo gem install os + - name: Build run: ./make.sh nat @@ -142,6 +148,9 @@ jobs: - name: Install dependencies run: opam install . --deps-only --locked + - name: Install os gem for operating system detection + run: sudo gem install os + - name: Setup Gobview run: ./make.sh setup_gobview diff --git a/.github/workflows/unlocked.yml b/.github/workflows/unlocked.yml index f3fe6cc558..81d1d3dc1c 100644 --- a/.github/workflows/unlocked.yml +++ b/.github/workflows/unlocked.yml @@ -57,6 +57,9 @@ jobs: - name: Install dependencies run: opam install . --deps-only --with-test + + - name: Install os gem for operating system detection + run: sudo gem install os - name: Install Apron dependencies if: ${{ matrix.apron }} @@ -118,6 +121,9 @@ jobs: - name: Install dependencies run: opam install . --deps-only --with-test + - name: Install os gem for operating system detection + run: sudo gem install os + - name: Install Apron dependencies run: | opam depext apron diff --git a/make.sh b/make.sh index 0f76759065..1ed5317aee 100755 --- a/make.sh +++ b/make.sh @@ -90,6 +90,7 @@ rule() { # Use `git commit -n` to temporarily bypass the hook if necessary. echo "Installing gem parallel (not needed for ./scripts/update_suite.rb -s)" sudo gem install parallel + sudo gem install os ;; headers) curl -L -O https://github.com/goblint/linux-headers/archive/master.tar.gz tar xf master.tar.gz && rm master.tar.gz diff --git a/scripts/update_suite.rb b/scripts/update_suite.rb index b21fb4b532..74fddc7b04 100755 --- a/scripts/update_suite.rb +++ b/scripts/update_suite.rb @@ -2,6 +2,7 @@ # gobopt environment variable can be used to override goblint defaults and PARAMs +require 'os' require 'find' require 'fileutils' require 'timeout' @@ -575,6 +576,8 @@ def run () end end +mac = OS.mac? + #processing the file information projects = [] project_ids = Set.new @@ -603,6 +606,7 @@ def run () lines = IO.readlines(path, :encoding => "UTF-8") next if not future and only.nil? and lines[0] =~ /SKIP/ + next if mac and lines[0] =~ /NOMAC/ next if marshal and lines[0] =~ /NOMARSHAL/ next if not has_linux_headers and lines[0] =~ /kernel/ if incremental then diff --git a/tests/regression/82-barrier/01-simple.c b/tests/regression/82-barrier/01-simple.c index 696e433962..285da1a6fb 100644 --- a/tests/regression/82-barrier/01-simple.c +++ b/tests/regression/82-barrier/01-simple.c @@ -1,4 +1,4 @@ -// PARAM: --set ana.activated[+] 'pthreadBarriers' +// NOMAC PARAM: --set ana.activated[+] 'pthreadBarriers' #include #include #include diff --git a/tests/regression/82-barrier/02-more.c b/tests/regression/82-barrier/02-more.c index cdabe740ea..53b4e99de2 100644 --- a/tests/regression/82-barrier/02-more.c +++ b/tests/regression/82-barrier/02-more.c @@ -1,4 +1,4 @@ -// PARAM: --set ana.activated[+] 'pthreadBarriers' +// NOMAC PARAM: --set ana.activated[+] 'pthreadBarriers' #include #include #include diff --git a/tests/regression/82-barrier/03-problem.c b/tests/regression/82-barrier/03-problem.c index d75245ccdd..2d80706b92 100644 --- a/tests/regression/82-barrier/03-problem.c +++ b/tests/regression/82-barrier/03-problem.c @@ -1,4 +1,4 @@ -// PARAM: --set ana.activated[+] 'pthreadBarriers' +// NOMAC PARAM: --set ana.activated[+] 'pthreadBarriers' #include #include #include diff --git a/tests/regression/82-barrier/04-challenge.c b/tests/regression/82-barrier/04-challenge.c index 2b50b3ad06..73d66e5c51 100644 --- a/tests/regression/82-barrier/04-challenge.c +++ b/tests/regression/82-barrier/04-challenge.c @@ -1,4 +1,4 @@ -// PARAM: --set ana.activated[+] 'pthreadBarriers' +// NOMAC PARAM: --set ana.activated[+] 'pthreadBarriers' #include #include #include diff --git a/tests/regression/82-barrier/05-mhp-not-enough.c b/tests/regression/82-barrier/05-mhp-not-enough.c index c627a4ff04..b289f3b0c0 100644 --- a/tests/regression/82-barrier/05-mhp-not-enough.c +++ b/tests/regression/82-barrier/05-mhp-not-enough.c @@ -1,4 +1,4 @@ -// PARAM: --set ana.activated[+] 'pthreadBarriers' +// NOMAC PARAM: --set ana.activated[+] 'pthreadBarriers' #include #include #include From a990b5f7fbcc225a5cba183ba29a3646c471eae3 Mon Sep 17 00:00:00 2001 From: Michael Schwarz Date: Wed, 25 Dec 2024 16:09:30 +0100 Subject: [PATCH 09/68] Remark that `os` gem is needed --- make.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/make.sh b/make.sh index 1ed5317aee..fddbf73ae0 100755 --- a/make.sh +++ b/make.sh @@ -75,7 +75,7 @@ rule() { ;; setup) echo "Make sure you have the following installed: opam >= 2.0.0, git, patch, m4, autoconf, libgmp-dev, libmpfr-dev, pkg-config" echo "For the --html output you also need: javac, ant, dot (graphviz)" - echo "For running the regression tests you also need: ruby, gem, curl" + echo "For running the regression tests you also need: ruby, gem, curl, and the `os` gem" echo "For reference see ./Dockerfile or ./scripts/travis-ci.sh" opam_setup ;; dev) From 27dd03001fc5d556b6d4d7fe154012f84e44869d Mon Sep 17 00:00:00 2001 From: Michael Schwarz Date: Wed, 25 Dec 2024 16:52:56 +0100 Subject: [PATCH 10/68] Make sound for multiprocess --- src/analyses/pthreadBarriers.ml | 66 ++++++++++--------- src/util/library/libraryDesc.ml | 2 +- src/util/library/libraryFunctions.ml | 2 +- tests/regression/82-barrier/06-multiprocess.c | 35 ++++++++++ 4 files changed, 73 insertions(+), 32 deletions(-) create mode 100644 tests/regression/82-barrier/06-multiprocess.c diff --git a/src/analyses/pthreadBarriers.ml b/src/analyses/pthreadBarriers.ml index a02c3332f4..049e0dbcf9 100644 --- a/src/analyses/pthreadBarriers.ml +++ b/src/analyses/pthreadBarriers.ml @@ -23,7 +23,8 @@ struct module TID = ThreadIdDomain.Thread module Waiters = SetDomain.ToppedSet (MHP) (struct let topname = "All MHP" end) - module G = Lattice.Prod (Capacity) (Waiters) + module Multiprocess = BoolDomain.MayBool + module G = Lattice.Prod3 (Multiprocess) (Capacity) (Waiters) let name () = "pthreadBarriers" module D = Lattice.Prod (Barriers) (MustBarriers) @@ -42,37 +43,40 @@ struct let barriers = possible_vinfos ask barrier in let mhp = MHP.current ask in let handle_one b = - man.sideg b (Capacity.bot (), Waiters.singleton mhp); + man.sideg b (Multiprocess.bot (), Capacity.bot (), Waiters.singleton mhp); let addr = ValueDomain.Addr.of_var b in - let (capacity, waiters) = man.global b in - let relevant_waiters = Waiters.filter (fun other -> MHP.may_happen_in_parallel mhp other) waiters in + let (multiprocess,capacity, waiters) = man.global b in let may_run = - if Waiters.exists MHP.may_be_non_unique_thread relevant_waiters then + if multiprocess then true else - let count = Waiters.cardinal relevant_waiters in - match capacity with - | `Lifted c -> - (* Add 1 as the thread calling wait at the moment will not be MHP with itself *) - let min_cap = (BatOption.default Z.zero (Capacity.I.minimal c)) in - if Z.leq min_cap Z.one then - true - else if min_cap = Z.of_int 2 && count = 1 then - true - else if Z.geq (Z.of_int (count + 1)) min_cap then - (* This is quite a cute problem: Do (min_cap-1) elements exist in the set such that - MHP is pairwise true? This solution is a sledgehammer, there should be something much - better algorithmically (beyond just laziness) *) - let waiters = Waiters.elements relevant_waiters in - let min_cap = Z.to_int min_cap in - let lists = List.init (min_cap - 1) (fun _ -> waiters) in - let candidates = BatList.n_cartesian_product lists in - List.exists (fun candidate -> - let pairwise = BatList.cartesian_product candidate candidate in - List.for_all (fun (a,b) -> MHP.may_happen_in_parallel a b) pairwise - ) candidates - else - false + let relevant_waiters = Waiters.filter (fun other -> MHP.may_happen_in_parallel mhp other) waiters in + if Waiters.exists MHP.may_be_non_unique_thread relevant_waiters then + true + else + let count = Waiters.cardinal relevant_waiters in + match capacity with + | `Lifted c -> + (* Add 1 as the thread calling wait at the moment will not be MHP with itself *) + let min_cap = (BatOption.default Z.zero (Capacity.I.minimal c)) in + if Z.leq min_cap Z.one then + true + else if min_cap = Z.of_int 2 && count = 1 then + true + else if Z.geq (Z.of_int (count + 1)) min_cap then + (* This is quite a cute problem: Do (min_cap-1) elements exist in the set such that + MHP is pairwise true? This solution is a sledgehammer, there should be something much + better algorithmically (beyond just laziness) *) + let waiters = Waiters.elements relevant_waiters in + let min_cap = Z.to_int min_cap in + let lists = List.init (min_cap - 1) (fun _ -> waiters) in + let candidates = BatList.n_cartesian_product lists in + List.exists (fun candidate -> + let pairwise = BatList.cartesian_product candidate candidate in + List.for_all (fun (a,b) -> MHP.may_happen_in_parallel a b) pairwise + ) candidates + else + false | _ -> true in if may_run then @@ -83,9 +87,11 @@ struct let (may, must) = List.fold_left (fun acc b-> D.join acc (handle_one b)) (D.bot ()) barriers in if Barriers.is_empty may then raise Analyses.Deadcode; (may, must) - | BarrierInit { barrier; count } -> + | BarrierInit { barrier; attr; count } -> + let multitprocess = not @@ Queries.AD.is_null @@ man.ask (Queries.MayPointTo attr) in + if multitprocess then M.warn "Barrier initialized with a non-NULL attr argument. Handled as if PTHREAD_PROCESS_SHARED potentially set."; let count = man.ask (Queries.EvalInt count) in - let publish_one b = man.sideg b (count, Waiters.bot ()) in + let publish_one b = man.sideg b (multitprocess, count, Waiters.bot ()) in let barriers = possible_vinfos (Analyses.ask_of_man man) barrier in List.iter publish_one barriers; man.local diff --git a/src/util/library/libraryDesc.ml b/src/util/library/libraryDesc.ml index 2da79dcc20..e439e97946 100644 --- a/src/util/library/libraryDesc.ml +++ b/src/util/library/libraryDesc.ml @@ -70,7 +70,7 @@ type special = | Wait of { cond: Cil.exp; mutex: Cil.exp; } | TimedWait of { cond: Cil.exp; mutex: Cil.exp; abstime: Cil.exp; (** Unused *) } | BarrierWait of Cil.exp - | BarrierInit of { barrier: Cil.exp; count: Cil.exp; } + | BarrierInit of { barrier: Cil.exp; attr:Cil.exp; count: Cil.exp; } | Math of { fun_args: math; } | Memset of { dest: Cil.exp; ch: Cil.exp; count: Cil.exp; } | Bzero of { dest: Cil.exp; count: Cil.exp; } diff --git a/src/util/library/libraryFunctions.ml b/src/util/library/libraryFunctions.ml index ab7d682483..1d36f69f3e 100644 --- a/src/util/library/libraryFunctions.ml +++ b/src/util/library/libraryFunctions.ml @@ -520,7 +520,7 @@ let pthread_descs_list: (string * LibraryDesc.t) list = LibraryDsl.[ ("pthread_getspecific", unknown ~attrs:[InvalidateGlobals] [drop "key" []]); ("pthread_key_create", unknown [drop "key" [w]; drop "destructor" [s]]); ("pthread_key_delete", unknown [drop "key" [f]]); - ("pthread_barrier_init", special [__ "barrier" []; __ "attr" []; __ "count" []] @@ fun barrier attr count -> BarrierInit {barrier; count}); + ("pthread_barrier_init", special [__ "barrier" []; __ "attr" []; __ "count" []] @@ fun barrier attr count -> BarrierInit {barrier; attr; count}); ("pthread_barrier_wait", special [__ "barrier" []] @@ fun barrier -> BarrierWait barrier); ("pthread_cancel", unknown [drop "thread" []]); ("pthread_testcancel", unknown []); diff --git a/tests/regression/82-barrier/06-multiprocess.c b/tests/regression/82-barrier/06-multiprocess.c new file mode 100644 index 0000000000..f55790cfab --- /dev/null +++ b/tests/regression/82-barrier/06-multiprocess.c @@ -0,0 +1,35 @@ +// NOMAC PARAM: --set ana.activated[+] 'pthreadBarriers' +#include +#include +#include + +int g; + +pthread_barrier_t barrier; + + +int main(int argc, char const *argv[]) +{ + int top; + int i = 0; + + pthread_barrierattr_t barattr; + pthread_barrierattr_setpshared(&barattr, PTHREAD_PROCESS_SHARED); + + pthread_barrier_init(&barrier, &barattr, 2); + + fork(); + pthread_t t1; + + if(top) { + pthread_barrier_wait(&barrier); + // Reachable if both processes go into this branch + i = 1; + } + + + __goblint_check(i == 0); //UNKNOWN! + + + return 0; +} From 24d61c00f86e91036f023aa19c6c8beb365ae25c Mon Sep 17 00:00:00 2001 From: Michael Schwarz Date: Wed, 25 Dec 2024 16:56:56 +0100 Subject: [PATCH 11/68] Fix indentation --- src/analyses/pthreadBarriers.ml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/analyses/pthreadBarriers.ml b/src/analyses/pthreadBarriers.ml index 049e0dbcf9..2f2a1bb0fb 100644 --- a/src/analyses/pthreadBarriers.ml +++ b/src/analyses/pthreadBarriers.ml @@ -65,19 +65,19 @@ struct true else if Z.geq (Z.of_int (count + 1)) min_cap then (* This is quite a cute problem: Do (min_cap-1) elements exist in the set such that - MHP is pairwise true? This solution is a sledgehammer, there should be something much - better algorithmically (beyond just laziness) *) + MHP is pairwise true? This solution is a sledgehammer, there should be something much + better algorithmically (beyond just laziness) *) let waiters = Waiters.elements relevant_waiters in let min_cap = Z.to_int min_cap in let lists = List.init (min_cap - 1) (fun _ -> waiters) in let candidates = BatList.n_cartesian_product lists in List.exists (fun candidate -> - let pairwise = BatList.cartesian_product candidate candidate in - List.for_all (fun (a,b) -> MHP.may_happen_in_parallel a b) pairwise - ) candidates + let pairwise = BatList.cartesian_product candidate candidate in + List.for_all (fun (a,b) -> MHP.may_happen_in_parallel a b) pairwise + ) candidates else false - | _ -> true + | _ -> true in if may_run then (Barriers.add addr may, Barriers.add addr must) From 8fe2e16e4b8611215dc56d7946cfff5b6be09b72 Mon Sep 17 00:00:00 2001 From: Michael Schwarz Date: Wed, 25 Dec 2024 18:10:50 +0100 Subject: [PATCH 12/68] Also consider locks --- src/analyses/pthreadBarriers.ml | 26 +++++++--- tests/regression/82-barrier/07-lockset.c | 39 +++++++++++++++ tests/regression/82-barrier/08-lockset-more.c | 47 +++++++++++++++++++ 3 files changed, 106 insertions(+), 6 deletions(-) create mode 100644 tests/regression/82-barrier/07-lockset.c create mode 100644 tests/regression/82-barrier/08-lockset-more.c diff --git a/src/analyses/pthreadBarriers.ml b/src/analyses/pthreadBarriers.ml index 2f2a1bb0fb..56c615aa53 100644 --- a/src/analyses/pthreadBarriers.ml +++ b/src/analyses/pthreadBarriers.ml @@ -22,7 +22,20 @@ struct module V = VarinfoV module TID = ThreadIdDomain.Thread - module Waiters = SetDomain.ToppedSet (MHP) (struct let topname = "All MHP" end) + + module MHPplusLock = struct + module Locks = LockDomain.MustLockset + + include Printable.Prod (MHP) (Locks) + let name () = "MHPplusLock" + + let mhp (mhp1, l1) (mhp2, l2) = + MHP.may_happen_in_parallel mhp1 mhp2 && Locks.is_empty (Locks.inter l1 l2) + + let may_be_non_unique_thread (mhp, _) = MHP.may_be_non_unique_thread mhp + end + + module Waiters = SetDomain.ToppedSet (MHPplusLock) (struct let topname = "All MHP" end) module Multiprocess = BoolDomain.MayBool module G = Lattice.Prod3 (Multiprocess) (Capacity) (Waiters) @@ -43,15 +56,16 @@ struct let barriers = possible_vinfos ask barrier in let mhp = MHP.current ask in let handle_one b = - man.sideg b (Multiprocess.bot (), Capacity.bot (), Waiters.singleton mhp); + let locks = man.ask (Queries.MustLockset) in + man.sideg b (Multiprocess.bot (), Capacity.bot (), Waiters.singleton (mhp, locks)); let addr = ValueDomain.Addr.of_var b in let (multiprocess,capacity, waiters) = man.global b in let may_run = if multiprocess then true else - let relevant_waiters = Waiters.filter (fun other -> MHP.may_happen_in_parallel mhp other) waiters in - if Waiters.exists MHP.may_be_non_unique_thread relevant_waiters then + let relevant_waiters = Waiters.filter (fun other -> MHPplusLock.mhp (mhp, locks) other) waiters in + if Waiters.exists MHPplusLock.may_be_non_unique_thread relevant_waiters then true else let count = Waiters.cardinal relevant_waiters in @@ -61,7 +75,7 @@ struct let min_cap = (BatOption.default Z.zero (Capacity.I.minimal c)) in if Z.leq min_cap Z.one then true - else if min_cap = Z.of_int 2 && count = 1 then + else if min_cap = Z.of_int 2 && count >= 1 then true else if Z.geq (Z.of_int (count + 1)) min_cap then (* This is quite a cute problem: Do (min_cap-1) elements exist in the set such that @@ -73,7 +87,7 @@ struct let candidates = BatList.n_cartesian_product lists in List.exists (fun candidate -> let pairwise = BatList.cartesian_product candidate candidate in - List.for_all (fun (a,b) -> MHP.may_happen_in_parallel a b) pairwise + List.for_all (fun (a,b) -> MHPplusLock.mhp a b) pairwise ) candidates else false diff --git a/tests/regression/82-barrier/07-lockset.c b/tests/regression/82-barrier/07-lockset.c new file mode 100644 index 0000000000..d1c68f3d7f --- /dev/null +++ b/tests/regression/82-barrier/07-lockset.c @@ -0,0 +1,39 @@ +// NOMAC PARAM: --set ana.activated[+] 'pthreadBarriers' +#include +#include +#include + +int g; + +pthread_barrier_t barrier; +pthread_mutex_t mutex; + +void* f1(void* ptr) { + pthread_mutex_lock(&mutex); + pthread_barrier_wait(&barrier); + pthread_mutex_unlock(&mutex); + return NULL; +} + +int main(int argc, char const *argv[]) +{ + int top; + int i = 0; + + pthread_barrier_init(&barrier, NULL, 2); + + pthread_t t1; + pthread_create(&t1,NULL,f1,NULL); + + if(top) { + pthread_mutex_lock(&mutex); + pthread_barrier_wait(&barrier); + // Deadlocks + pthread_mutex_unlock(&mutex); + i = 1; + } + + __goblint_check(i == 0); + + return 0; +} diff --git a/tests/regression/82-barrier/08-lockset-more.c b/tests/regression/82-barrier/08-lockset-more.c new file mode 100644 index 0000000000..a33ecc1a78 --- /dev/null +++ b/tests/regression/82-barrier/08-lockset-more.c @@ -0,0 +1,47 @@ +// NOMAC PARAM: --set ana.activated[+] 'pthreadBarriers' +#include +#include +#include + +int g; + +pthread_barrier_t barrier; +pthread_mutex_t mutex; + +void* f1(void* ptr) { + pthread_mutex_lock(&mutex); + pthread_barrier_wait(&barrier); + pthread_mutex_unlock(&mutex); + return NULL; +} + +void* f2(void* ptr) { + pthread_mutex_lock(&mutex); + pthread_barrier_wait(&barrier); + pthread_mutex_unlock(&mutex); + return NULL; +} + +int main(int argc, char const *argv[]) +{ + int top; + int i = 0; + + pthread_barrier_init(&barrier, NULL, 2); + + pthread_t t1; + pthread_create(&t1,NULL,f1,NULL); + + pthread_t t2; + pthread_create(&t2,NULL,f2,NULL); + + + if(top) { + pthread_barrier_wait(&barrier); + i = 1; + } + + __goblint_check(i == 0); //UNKNOWN! + + return 0; +} From 05d2f60ffcc0faae7f7673a30822cd29f42603e8 Mon Sep 17 00:00:00 2001 From: Michael Schwarz Date: Wed, 25 Dec 2024 19:15:04 +0100 Subject: [PATCH 13/68] Minimal race handling --- src/analyses/pthreadBarriers.ml | 54 ++++++++++++++++++++------- tests/regression/82-barrier/09-race.c | 36 ++++++++++++++++++ 2 files changed, 77 insertions(+), 13 deletions(-) create mode 100644 tests/regression/82-barrier/09-race.c diff --git a/src/analyses/pthreadBarriers.ml b/src/analyses/pthreadBarriers.ml index 56c615aa53..6c8a823658 100644 --- a/src/analyses/pthreadBarriers.ml +++ b/src/analyses/pthreadBarriers.ml @@ -21,7 +21,7 @@ struct include Analyses.IdentitySpec module V = VarinfoV - module TID = ThreadIdDomain.Thread + module TID = ThreadIdDomain.ThreadLifted module MHPplusLock = struct module Locks = LockDomain.MustLockset @@ -32,6 +32,8 @@ struct let mhp (mhp1, l1) (mhp2, l2) = MHP.may_happen_in_parallel mhp1 mhp2 && Locks.is_empty (Locks.inter l1 l2) + let tid ((mhp:MHP.t), _) = mhp.tid + let may_be_non_unique_thread (mhp, _) = MHP.may_be_non_unique_thread mhp end @@ -40,7 +42,9 @@ struct module G = Lattice.Prod3 (Multiprocess) (Capacity) (Waiters) let name () = "pthreadBarriers" - module D = Lattice.Prod (Barriers) (MustBarriers) + + module MustObserved = MapDomain.MapTop_LiftBot (TID) (MustBarriers) + module D = Lattice.Prod (Barriers) (MustObserved) include Analyses.ValueContexts(D) @@ -60,13 +64,13 @@ struct man.sideg b (Multiprocess.bot (), Capacity.bot (), Waiters.singleton (mhp, locks)); let addr = ValueDomain.Addr.of_var b in let (multiprocess,capacity, waiters) = man.global b in - let may_run = + let may_run, must = if multiprocess then - true + true, must else let relevant_waiters = Waiters.filter (fun other -> MHPplusLock.mhp (mhp, locks) other) waiters in if Waiters.exists MHPplusLock.may_be_non_unique_thread relevant_waiters then - true + true, must else let count = Waiters.cardinal relevant_waiters in match capacity with @@ -74,9 +78,14 @@ struct (* Add 1 as the thread calling wait at the moment will not be MHP with itself *) let min_cap = (BatOption.default Z.zero (Capacity.I.minimal c)) in if Z.leq min_cap Z.one then - true + true, must + else if min_cap = Z.of_int 2 && count = 1 then + let elem = Waiters.choose relevant_waiters in + let curr = MustObserved.find (MHPplusLock.tid elem) must in + let must' = MustObserved.add (MHPplusLock.tid elem) (Barriers.add addr curr) must in + true, must' else if min_cap = Z.of_int 2 && count >= 1 then - true + true, must else if Z.geq (Z.of_int (count + 1)) min_cap then (* This is quite a cute problem: Do (min_cap-1) elements exist in the set such that MHP is pairwise true? This solution is a sledgehammer, there should be something much @@ -88,13 +97,13 @@ struct List.exists (fun candidate -> let pairwise = BatList.cartesian_product candidate candidate in List.for_all (fun (a,b) -> MHPplusLock.mhp a b) pairwise - ) candidates + ) candidates, must else - false - | _ -> true + false, must + | _ -> true, must in if may_run then - (Barriers.add addr may, Barriers.add addr must) + (Barriers.add addr may, must) else D.bot () in @@ -111,9 +120,28 @@ struct man.local | _ -> man.local - let startstate v = (Barriers.empty (), Barriers.empty ()) + let startstate v = (Barriers.empty (), MustObserved.empty ()) let threadenter man ~multiple lval f args = [man.local] - let exitstate v = (Barriers.empty (), Barriers.empty ()) + let exitstate v = (Barriers.empty (), MustObserved.empty ()) + + module A = + struct + include Lattice.Prod3 (Barriers) (MustObserved) (TID) + let name () = "barriers" + let may_race (may_await_t1, must_observed_by_t1, t1) (may_await_t2, must_observed_by_t2, t2) = + let observed_from_t2 = MustObserved.find t2 must_observed_by_t1 in + if not (Barriers.subset observed_from_t2 may_await_t2) then + false + else + let observed_from_t1 = MustObserved.find t1 must_observed_by_t2 in + Barriers.subset observed_from_t1 may_await_t1 + let should_print f = true + end + + let access man (a: Queries.access) = + let (may,must) = man.local in + let mhp = MHP.current (Analyses.ask_of_man man) in + (may, must, mhp.tid) end let _ = diff --git a/tests/regression/82-barrier/09-race.c b/tests/regression/82-barrier/09-race.c new file mode 100644 index 0000000000..fad6ad6243 --- /dev/null +++ b/tests/regression/82-barrier/09-race.c @@ -0,0 +1,36 @@ +// NOMAC PARAM: --set ana.activated[+] 'pthreadBarriers' +#include +#include +#include + +int g; +int h; + +pthread_barrier_t barrier; +pthread_mutex_t mutex; + +void* f1(void* ptr) { + g = 2; //NORACE + h = 3; //RACE + pthread_barrier_wait(&barrier); + + return NULL; +} + +int main(int argc, char const *argv[]) +{ + int top; + int i = 0; + + pthread_barrier_init(&barrier, NULL, 2); + + pthread_t t1; + pthread_create(&t1,NULL,f1,NULL); + + h = 5; //RACE + + pthread_barrier_wait(&barrier); + g = 3; //NORACE + + return 0; +} From 1b3a0d8ebdf9107c285cbdcb229d6a7304536cb0 Mon Sep 17 00:00:00 2001 From: Michael Schwarz Date: Wed, 25 Dec 2024 19:44:26 +0100 Subject: [PATCH 14/68] Fix pairwise MHP check --- src/analyses/pthreadBarriers.ml | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/analyses/pthreadBarriers.ml b/src/analyses/pthreadBarriers.ml index 6c8a823658..52e040544f 100644 --- a/src/analyses/pthreadBarriers.ml +++ b/src/analyses/pthreadBarriers.ml @@ -90,14 +90,20 @@ struct (* This is quite a cute problem: Do (min_cap-1) elements exist in the set such that MHP is pairwise true? This solution is a sledgehammer, there should be something much better algorithmically (beyond just laziness) *) + ( let waiters = Waiters.elements relevant_waiters in let min_cap = Z.to_int min_cap in + M.warn "entered case min_cap is %i, waiters is %i" min_cap (List.length waiters); let lists = List.init (min_cap - 1) (fun _ -> waiters) in let candidates = BatList.n_cartesian_product lists in - List.exists (fun candidate -> - let pairwise = BatList.cartesian_product candidate candidate in - List.for_all (fun (a,b) -> MHPplusLock.mhp a b) pairwise - ) candidates, must + let pred = List.exists (fun candidate -> + let rec do_it = function + | [] -> true + | x::xs -> List.for_all (fun y -> MHPplusLock.mhp x y) xs && do_it xs + in + do_it candidate + ) candidates in + pred, must) else false, must | _ -> true, must From 7e98213918bc92e59a13bc9eb341872f7ce1d691 Mon Sep 17 00:00:00 2001 From: Michael Schwarz Date: Wed, 25 Dec 2024 19:57:53 +0100 Subject: [PATCH 15/68] Add case for more waiters --- src/analyses/pthreadBarriers.ml | 39 +++++++++++++++------- tests/regression/82-barrier/10-several.c | 36 ++++++++++++++++++++ tests/regression/82-barrier/11-race-more.c | 37 ++++++++++++++++++++ 3 files changed, 100 insertions(+), 12 deletions(-) create mode 100644 tests/regression/82-barrier/10-several.c create mode 100644 tests/regression/82-barrier/11-race-more.c diff --git a/src/analyses/pthreadBarriers.ml b/src/analyses/pthreadBarriers.ml index 52e040544f..83e253f66f 100644 --- a/src/analyses/pthreadBarriers.ml +++ b/src/analyses/pthreadBarriers.ml @@ -91,19 +91,34 @@ struct MHP is pairwise true? This solution is a sledgehammer, there should be something much better algorithmically (beyond just laziness) *) ( - let waiters = Waiters.elements relevant_waiters in - let min_cap = Z.to_int min_cap in - M.warn "entered case min_cap is %i, waiters is %i" min_cap (List.length waiters); - let lists = List.init (min_cap - 1) (fun _ -> waiters) in - let candidates = BatList.n_cartesian_product lists in - let pred = List.exists (fun candidate -> - let rec do_it = function - | [] -> true - | x::xs -> List.for_all (fun y -> MHPplusLock.mhp x y) xs && do_it xs + let waiters = Waiters.elements relevant_waiters in + let min_cap = Z.to_int min_cap in + let lists = List.init (min_cap - 1) (fun _ -> waiters) in + let candidates = BatList.n_cartesian_product lists in + let pred = List.exists (fun candidate -> + let rec do_it = function + | [] -> true + | x::xs -> List.for_all (fun y -> MHPplusLock.mhp x y) xs && do_it xs + in + do_it candidate + ) candidates + in + if pred then + (* limit to this case to avoid having to construct all permutations above *) + let must = if (List.length waiters) = min_cap-1 then + List.fold_left (fun acc elem -> + let tid = MHPplusLock.tid elem in + let curr = MustObserved.find tid acc in + let must' = MustObserved.add tid (Barriers.add addr curr) acc in + must' + ) must waiters + else + must in - do_it candidate - ) candidates in - pred, must) + true, must + else + false, must + ) else false, must | _ -> true, must diff --git a/tests/regression/82-barrier/10-several.c b/tests/regression/82-barrier/10-several.c new file mode 100644 index 0000000000..6fc9f57681 --- /dev/null +++ b/tests/regression/82-barrier/10-several.c @@ -0,0 +1,36 @@ +// NOMAC PARAM: --set ana.activated[+] 'pthreadBarriers' +#include +#include +#include + +int g; + +pthread_barrier_t barrier; + +void* f1(void* ptr) { + pthread_barrier_wait(&barrier); + + return NULL; +} + +int main(int argc, char const *argv[]) +{ + int top; + int i = 0; + + pthread_barrier_init(&barrier, NULL, 4); + + pthread_t t1, t2, t3; + pthread_create(&t1,NULL,f1,NULL); + pthread_create(&t2,NULL,f1,NULL); + pthread_create(&t3,NULL,f1,NULL); + + if(top) { + pthread_barrier_wait(&barrier); + i = 1; + } + + __goblint_check(i == 0); //UNKNOWN! + + return 0; +} diff --git a/tests/regression/82-barrier/11-race-more.c b/tests/regression/82-barrier/11-race-more.c new file mode 100644 index 0000000000..ed6c7ef29d --- /dev/null +++ b/tests/regression/82-barrier/11-race-more.c @@ -0,0 +1,37 @@ +// NOMAC PARAM: --set ana.activated[+] 'pthreadBarriers' +#include +#include +#include + +int g; + +pthread_barrier_t barrier; +pthread_mutex_t mutex; + +void* f1(void* ptr) { + pthread_mutex_lock(&mutex); + g = 4711; //NORACE + pthread_mutex_unlock(&mutex); + pthread_barrier_wait(&barrier); + + return NULL; +} + +int main(int argc, char const *argv[]) +{ + int top; + int i = 0; + + pthread_barrier_init(&barrier, NULL, 4); + + pthread_t t1, t2, t3; + pthread_create(&t1,NULL,f1,NULL); + pthread_create(&t2,NULL,f1,NULL); + pthread_create(&t3,NULL,f1,NULL); + + pthread_barrier_wait(&barrier); + + g = 3; //NORACE + + return 0; +} From 1b4beae60e768f729843a600d387d5bd00fe0911 Mon Sep 17 00:00:00 2001 From: Michael Schwarz Date: Wed, 25 Dec 2024 20:01:08 +0100 Subject: [PATCH 16/68] Get rid of overcomplicated logic --- src/analyses/pthreadBarriers.ml | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/analyses/pthreadBarriers.ml b/src/analyses/pthreadBarriers.ml index 83e253f66f..4ea5f1540a 100644 --- a/src/analyses/pthreadBarriers.ml +++ b/src/analyses/pthreadBarriers.ml @@ -79,13 +79,6 @@ struct let min_cap = (BatOption.default Z.zero (Capacity.I.minimal c)) in if Z.leq min_cap Z.one then true, must - else if min_cap = Z.of_int 2 && count = 1 then - let elem = Waiters.choose relevant_waiters in - let curr = MustObserved.find (MHPplusLock.tid elem) must in - let must' = MustObserved.add (MHPplusLock.tid elem) (Barriers.add addr curr) must in - true, must' - else if min_cap = Z.of_int 2 && count >= 1 then - true, must else if Z.geq (Z.of_int (count + 1)) min_cap then (* This is quite a cute problem: Do (min_cap-1) elements exist in the set such that MHP is pairwise true? This solution is a sledgehammer, there should be something much From 1bfb9857b586969f701c32ff03439faa70ddb532 Mon Sep 17 00:00:00 2001 From: Michael Schwarz Date: Wed, 25 Dec 2024 20:20:39 +0100 Subject: [PATCH 17/68] Cleanup --- src/analyses/pthreadBarriers.ml | 68 +++++++++++++++------------------ 1 file changed, 31 insertions(+), 37 deletions(-) diff --git a/src/analyses/pthreadBarriers.ml b/src/analyses/pthreadBarriers.ml index 4ea5f1540a..e26b657805 100644 --- a/src/analyses/pthreadBarriers.ml +++ b/src/analyses/pthreadBarriers.ml @@ -60,35 +60,37 @@ struct let barriers = possible_vinfos ask barrier in let mhp = MHP.current ask in let handle_one b = - let locks = man.ask (Queries.MustLockset) in - man.sideg b (Multiprocess.bot (), Capacity.bot (), Waiters.singleton (mhp, locks)); - let addr = ValueDomain.Addr.of_var b in - let (multiprocess,capacity, waiters) = man.global b in - let may_run, must = + try + let locks = man.ask (Queries.MustLockset) in + man.sideg b (Multiprocess.bot (), Capacity.bot (), Waiters.singleton (mhp, locks)); + let addr = ValueDomain.Addr.of_var b in + let (multiprocess, capacity, waiters) = man.global b in + let may = Barriers.add addr may in if multiprocess then - true, must + (may, must) else - let relevant_waiters = Waiters.filter (fun other -> MHPplusLock.mhp (mhp, locks) other) waiters in + let relevant_waiters = Waiters.filter (fun other -> MHPplusLock.mhp (mhp, locks) other) waiters in if Waiters.exists MHPplusLock.may_be_non_unique_thread relevant_waiters then - true, must + (may, must) else - let count = Waiters.cardinal relevant_waiters in match capacity with + | `Top | `Bot -> (may, must) | `Lifted c -> + let count = Waiters.cardinal relevant_waiters in (* Add 1 as the thread calling wait at the moment will not be MHP with itself *) let min_cap = (BatOption.default Z.zero (Capacity.I.minimal c)) in if Z.leq min_cap Z.one then - true, must + (may, must) else if Z.geq (Z.of_int (count + 1)) min_cap then (* This is quite a cute problem: Do (min_cap-1) elements exist in the set such that - MHP is pairwise true? This solution is a sledgehammer, there should be something much - better algorithmically (beyond just laziness) *) - ( + MHP is pairwise true? This solution is a sledgehammer, there should be something much + better algorithmically (beyond just laziness) *) + let must = let waiters = Waiters.elements relevant_waiters in let min_cap = Z.to_int min_cap in let lists = List.init (min_cap - 1) (fun _ -> waiters) in let candidates = BatList.n_cartesian_product lists in - let pred = List.exists (fun candidate -> + let can_proceed = List.exists (fun candidate -> let rec do_it = function | [] -> true | x::xs -> List.for_all (fun y -> MHPplusLock.mhp x y) xs && do_it xs @@ -96,30 +98,22 @@ struct do_it candidate ) candidates in - if pred then - (* limit to this case to avoid having to construct all permutations above *) - let must = if (List.length waiters) = min_cap-1 then - List.fold_left (fun acc elem -> - let tid = MHPplusLock.tid elem in - let curr = MustObserved.find tid acc in - let must' = MustObserved.add tid (Barriers.add addr curr) acc in - must' - ) must waiters - else - must - in - true, must - else - false, must - ) + if not can_proceed then raise Analyses.Deadcode; + (* limit to this case to avoid having to construct all permutations above *) + if List.length waiters = min_cap - 1 then + List.fold_left (fun acc elem -> + let tid = MHPplusLock.tid elem in + let curr = MustObserved.find tid acc in + let must' = MustObserved.add tid (Barriers.add addr curr) acc in + must' + ) must waiters + else + must + in + (may, must) else - false, must - | _ -> true, must - in - if may_run then - (Barriers.add addr may, must) - else - D.bot () + raise Analyses.Deadcode; + with Analyses.Deadcode -> D.bot () in let (may, must) = List.fold_left (fun acc b-> D.join acc (handle_one b)) (D.bot ()) barriers in if Barriers.is_empty may then raise Analyses.Deadcode; From 35bec2d199f888e034b7e6fe08361e7988304ea9 Mon Sep 17 00:00:00 2001 From: Michael Schwarz Date: Fri, 17 Jan 2025 14:26:12 +0100 Subject: [PATCH 18/68] Fix `List.length` call --- src/analyses/pthreadBarriers.ml | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/analyses/pthreadBarriers.ml b/src/analyses/pthreadBarriers.ml index e26b657805..1cea151fed 100644 --- a/src/analyses/pthreadBarriers.ml +++ b/src/analyses/pthreadBarriers.ml @@ -13,7 +13,7 @@ struct module MustBarriers = struct include Lattice.Reverse (Barriers) - let name () = "mustBarriers" + let name () = "mustBarriers" end module Capacity = Queries.ID @@ -29,7 +29,7 @@ struct include Printable.Prod (MHP) (Locks) let name () = "MHPplusLock" - let mhp (mhp1, l1) (mhp2, l2) = + let mhp (mhp1, l1) (mhp2, l2) = MHP.may_happen_in_parallel mhp1 mhp2 && Locks.is_empty (Locks.inter l1 l2) let tid ((mhp:MHP.t), _) = mhp.tid @@ -60,7 +60,7 @@ struct let barriers = possible_vinfos ask barrier in let mhp = MHP.current ask in let handle_one b = - try + try let locks = man.ask (Queries.MustLockset) in man.sideg b (Multiprocess.bot (), Capacity.bot (), Waiters.singleton (mhp, locks)); let addr = ValueDomain.Addr.of_var b in @@ -69,23 +69,23 @@ struct if multiprocess then (may, must) else - let relevant_waiters = Waiters.filter (fun other -> MHPplusLock.mhp (mhp, locks) other) waiters in + let relevant_waiters = Waiters.filter (fun other -> MHPplusLock.mhp (mhp, locks) other) waiters in if Waiters.exists MHPplusLock.may_be_non_unique_thread relevant_waiters then - (may, must) + (may, must) else match capacity with | `Top | `Bot -> (may, must) - | `Lifted c -> + | `Lifted c -> let count = Waiters.cardinal relevant_waiters in (* Add 1 as the thread calling wait at the moment will not be MHP with itself *) let min_cap = (BatOption.default Z.zero (Capacity.I.minimal c)) in if Z.leq min_cap Z.one then (may, must) else if Z.geq (Z.of_int (count + 1)) min_cap then - (* This is quite a cute problem: Do (min_cap-1) elements exist in the set such that + (* This is quite a cute problem: Do (min_cap-1) elements exist in the set such that MHP is pairwise true? This solution is a sledgehammer, there should be something much better algorithmically (beyond just laziness) *) - let must = + let must = let waiters = Waiters.elements relevant_waiters in let min_cap = Z.to_int min_cap in let lists = List.init (min_cap - 1) (fun _ -> waiters) in @@ -100,14 +100,14 @@ struct in if not can_proceed then raise Analyses.Deadcode; (* limit to this case to avoid having to construct all permutations above *) - if List.length waiters = min_cap - 1 then - List.fold_left (fun acc elem -> + if BatList.compare_length_with waiters (min_cap - 1) = 0 then + List.fold_left (fun acc elem -> let tid = MHPplusLock.tid elem in let curr = MustObserved.find tid acc in let must' = MustObserved.add tid (Barriers.add addr curr) acc in must' ) must waiters - else + else must in (may, must) @@ -122,7 +122,7 @@ struct let multitprocess = not @@ Queries.AD.is_null @@ man.ask (Queries.MayPointTo attr) in if multitprocess then M.warn "Barrier initialized with a non-NULL attr argument. Handled as if PTHREAD_PROCESS_SHARED potentially set."; let count = man.ask (Queries.EvalInt count) in - let publish_one b = man.sideg b (multitprocess, count, Waiters.bot ()) in + let publish_one b = man.sideg b (multitprocess, count, Waiters.bot ()) in let barriers = possible_vinfos (Analyses.ask_of_man man) barrier in List.iter publish_one barriers; man.local @@ -146,7 +146,7 @@ struct let should_print f = true end - let access man (a: Queries.access) = + let access man (a: Queries.access) = let (may,must) = man.local in let mhp = MHP.current (Analyses.ask_of_man man) in (may, must, mhp.tid) From ea90d39aed8d8c8068709ce0b1e715ed097c66b1 Mon Sep 17 00:00:00 2001 From: Michael Schwarz Date: Fri, 24 Jan 2025 15:28:48 +0100 Subject: [PATCH 19/68] Add first handling to constraints --- src/framework/constraints.ml | 24 +++++++++++++++--------- src/util/library/libraryDesc.ml | 1 + src/util/library/libraryFunctions.ml | 10 +++++----- src/util/library/libraryFunctions.mli | 2 +- tests/regression/83-once/01-sanity.c | 24 ++++++++++++++++++++++++ 5 files changed, 46 insertions(+), 15 deletions(-) create mode 100644 tests/regression/83-once/01-sanity.c diff --git a/src/framework/constraints.ml b/src/framework/constraints.ml index c7cfce95d2..9ff295355e 100644 --- a/src/framework/constraints.ml +++ b/src/framework/constraints.ml @@ -245,7 +245,7 @@ struct let tf_special_call man lv f args = S.special man lv f args - let tf_proc var edge prev_node lv e args getl sidel getg sideg d = + let rec tf_proc var edge prev_node lv e args getl sidel getg sideg d = let man, r, spawns = common_man var edge prev_node d getl sidel getg sideg in let functions = match e with @@ -266,14 +266,20 @@ struct (* Check whether number of arguments fits. *) (* If params is None, the function or its parameters are not declared, so we still analyze the unknown function call. *) if Option.is_none params || p_length = arg_length || (var_arg && arg_length >= p_length) then - begin Some (match Cilfacade.find_varinfo_fundec f with - | fd when LibraryFunctions.use_special f.vname -> - M.info ~category:Analyzer "Using special for defined function %s" f.vname; - tf_special_call man lv f args - | fd -> - tf_normal_call man lv e fd args getl sidel getg sideg - | exception Not_found -> - tf_special_call man lv f args) + begin + let is_once = LibraryFunctions.find ~nowarn:true f in + match is_once.special args with + | Once { once_control; init_routine } -> + Some (D.join d (tf_proc var edge prev_node None init_routine [] getl sidel getg sideg d)) + | _ -> + Some (match Cilfacade.find_varinfo_fundec f with + | fd when LibraryFunctions.use_special f.vname -> + M.info ~category:Analyzer "Using special for defined function %s" f.vname; + tf_special_call man lv f args + | fd -> + tf_normal_call man lv e fd args getl sidel getg sideg + | exception Not_found -> + tf_special_call man lv f args) end else begin let geq = if var_arg then ">=" else "" in diff --git a/src/util/library/libraryDesc.ml b/src/util/library/libraryDesc.ml index 6f34de1864..85de9d0f05 100644 --- a/src/util/library/libraryDesc.ml +++ b/src/util/library/libraryDesc.ml @@ -84,6 +84,7 @@ type special = | Longjmp of { env: Cil.exp; value: Cil.exp; } | Bounded of { exp: Cil.exp} (** Used to check for bounds for termination analysis. *) | Rand + | Once of { once_control: Cil.exp; init_routine: Cil.exp; } | Unknown (** Anything not belonging to other types. *) (* TODO: rename to Other? *) diff --git a/src/util/library/libraryFunctions.ml b/src/util/library/libraryFunctions.ml index 6643b58eef..1fa4ecc8e9 100644 --- a/src/util/library/libraryFunctions.ml +++ b/src/util/library/libraryFunctions.ml @@ -464,6 +464,7 @@ let pthread_descs_list: (string * LibraryDesc.t) list = LibraryDsl.[ ("pthread_create", special [__ "thread" [w]; drop "attr" [r]; __ "start_routine" [s]; __ "arg" []] @@ fun thread start_routine arg -> ThreadCreate { thread; start_routine; arg; multiple = false }); (* For precision purposes arg is not considered accessed here. Instead all accesses (if any) come from actually analyzing start_routine. *) ("pthread_exit", special [__ "retval" []] @@ fun retval -> ThreadExit { ret_val = retval }); (* Doesn't dereference the void* itself, but just passes to pthread_join. *) ("pthread_join", special [__ "thread" []; __ "retval" [w]] @@ fun thread retval -> ThreadJoin {thread; ret_var = retval}); + ("pthread_once", special [__ "once_control" []; __ "init_routine" []] @@ fun once_control init_routine -> Once {once_control; init_routine}); ("pthread_kill", unknown [drop "thread" []; drop "sig" []]); ("pthread_equal", unknown [drop "t1" []; drop "t2" []]); ("pthread_cond_init", unknown [drop "cond" [w]; drop "attr" [r]]); @@ -1298,7 +1299,7 @@ let is_safe_uncalled fn_name = List.exists (fun r -> Str.string_match r fn_name 0) kernel_safe_uncalled_regex -let unknown_desc f : LibraryDesc.t = +let unknown_desc f ~nowarn : LibraryDesc.t = let accs args : (LibraryDesc.Access.t * 'a list) list = [ ({ kind = Read; deep = true; }, if GobConfig.get_bool "sem.unknown_function.read.args" then args else []); ({ kind = Write; deep = true; }, if GobConfig.get_bool "sem.unknown_function.invalidate.args" then args else []); @@ -1314,7 +1315,7 @@ let unknown_desc f : LibraryDesc.t = [] in (* TODO: remove hack when all classify are migrated *) - if not (CilType.Varinfo.equal f dummyFunDec.svar) && not (use_special f.vname) then ( + if not nowarn && not (CilType.Varinfo.equal f dummyFunDec.svar) && not (use_special f.vname) then ( M.msg_final Error ~category:Imprecise ~tags:[Category Unsound] "Function definition missing"; M.error ~category:Imprecise ~tags:[Category Unsound] "Function definition missing for %s" f.vname ); @@ -1324,12 +1325,11 @@ let unknown_desc f : LibraryDesc.t = special = fun _ -> Unknown; } -let find f = +let find ?(nowarn=false) f = let name = f.vname in match Hashtbl.find_option (ResettableLazy.force activated_library_descs) name with | Some desc -> desc - | None -> unknown_desc f - + | None -> unknown_desc ~nowarn f let is_special fv = if use_special fv.vname then diff --git a/src/util/library/libraryFunctions.mli b/src/util/library/libraryFunctions.mli index 9a8e55a48a..7eb9c531fe 100644 --- a/src/util/library/libraryFunctions.mli +++ b/src/util/library/libraryFunctions.mli @@ -11,7 +11,7 @@ val use_special : string -> bool val is_safe_uncalled : string -> bool (** Find library function descriptor for {e special} function (as per {!is_special}). *) -val find: Cil.varinfo -> LibraryDesc.t +val find: ?nowarn:bool -> Cil.varinfo -> LibraryDesc.t val is_special: Cil.varinfo -> bool (** Check if function is treated specially. *) diff --git a/tests/regression/83-once/01-sanity.c b/tests/regression/83-once/01-sanity.c new file mode 100644 index 0000000000..954f70dd4b --- /dev/null +++ b/tests/regression/83-once/01-sanity.c @@ -0,0 +1,24 @@ +// PARAM: --set pre.cppflags[+] "-DGOBLINT_NO_PTHREAD_ONCE" +#include +#include + +int g; +pthread_once_t once = PTHREAD_ONCE_INIT; +pthread_mutex_t mutex1 = PTHREAD_MUTEX_INITIALIZER; + +void fun() { + g++; +} + + +int main(void) { + pthread_t id; + + pthread_once(&once, fun); + pthread_once(&once, fun); + + // This fails if the (actual) case that it is not executed twice is ignored. + __goblint_check(g == 1); //TODO + + return 0; +} From 383ad9495d416b397e7d02b9d998a5ce2ab78b29 Mon Sep 17 00:00:00 2001 From: Michael Schwarz Date: Fri, 24 Jan 2025 16:12:36 +0100 Subject: [PATCH 20/68] Fix failing test --- src/framework/constraints.ml | 8 ++++++-- src/util/library/libraryDsl.ml | 2 ++ src/util/library/libraryDsl.mli | 2 ++ 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/framework/constraints.ml b/src/framework/constraints.ml index 9ff295355e..cb510501b7 100644 --- a/src/framework/constraints.ml +++ b/src/framework/constraints.ml @@ -258,6 +258,9 @@ struct let ad = man.ask (Queries.EvalFunvar e) in Queries.AD.to_var_may ad (* TODO: don't convert, handle UnknownPtr below *) in + let once once_control init_routine = + D.join d (tf_proc var edge prev_node None init_routine [] getl sidel getg sideg d) + in let one_function f = match f.vtype with | TFun (_, params, var_arg, _) -> @@ -270,8 +273,9 @@ struct let is_once = LibraryFunctions.find ~nowarn:true f in match is_once.special args with | Once { once_control; init_routine } -> - Some (D.join d (tf_proc var edge prev_node None init_routine [] getl sidel getg sideg d)) - | _ -> + Some (once once_control init_routine) + | _ + | exception LibraryDsl.Expected _-> (* propagate weirdness inside *) Some (match Cilfacade.find_varinfo_fundec f with | fd when LibraryFunctions.use_special f.vname -> M.info ~category:Analyzer "Using special for defined function %s" f.vname; diff --git a/src/util/library/libraryDsl.ml b/src/util/library/libraryDsl.ml index a380714dc0..240c318579 100644 --- a/src/util/library/libraryDsl.ml +++ b/src/util/library/libraryDsl.ml @@ -30,6 +30,8 @@ struct | [] -> fail "^::" end +exception Expected = Pattern.Expected + type access = | Access of LibraryDesc.Access.t | If of (unit -> bool) * access diff --git a/src/util/library/libraryDsl.mli b/src/util/library/libraryDsl.mli index 42c300af8e..2eed55666d 100644 --- a/src/util/library/libraryDsl.mli +++ b/src/util/library/libraryDsl.mli @@ -82,3 +82,5 @@ val c_deep: access (** Conditional access, e.g. on an option. *) val if_: (unit -> bool) -> access -> access + +exception Expected of string From ff411e44f34b6a7fe5f5047886d6fd7053f0eb16 Mon Sep 17 00:00:00 2001 From: Michael Schwarz Date: Fri, 24 Jan 2025 16:34:22 +0100 Subject: [PATCH 21/68] More events & constraints --- src/domains/events.ml | 8 +++++++- src/framework/constraints.ml | 16 +++++++++++++++- 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/src/domains/events.ml b/src/domains/events.ml index cc4af83819..205b81e443 100644 --- a/src/domains/events.ml +++ b/src/domains/events.ml @@ -16,6 +16,8 @@ type t = | Assert of exp | Unassume of {exp: CilType.Exp.t; tokens: WideningToken.t list} | Longjmped of {lval: CilType.Lval.t option} + | EnterOnce of {once_control: CilType.Exp.t; tf:bool} + | LeaveOnce of {once_control: CilType.Exp.t} (** Should event be emitted after transfer function raises [Deadcode]? *) let emit_on_deadcode = function @@ -31,7 +33,9 @@ let emit_on_deadcode = function | UpdateExpSplit _ (* Pointless to split on dead. *) | Unassume _ (* Avoid spurious writes. *) | Assert _ (* Pointless to refine dead. *) - | Longjmped _ -> + | Longjmped _ + | EnterOnce _ + | LeaveOnce _ -> false let pretty () = function @@ -47,3 +51,5 @@ let pretty () = function | Assert exp -> dprintf "Assert %a" d_exp exp | Unassume {exp; tokens} -> dprintf "Unassume {exp=%a; tokens=%a}" d_exp exp (d_list ", " WideningToken.pretty) tokens | Longjmped {lval} -> dprintf "Longjmped {lval=%a}" (docOpt (CilType.Lval.pretty ())) lval + | EnterOnce {once_control; tf} -> dprintf "todo" + | LeaveOnce {once_control} -> dprintf "todo" diff --git a/src/framework/constraints.ml b/src/framework/constraints.ml index cb510501b7..d2c1c8215b 100644 --- a/src/framework/constraints.ml +++ b/src/framework/constraints.ml @@ -259,7 +259,21 @@ struct Queries.AD.to_var_may ad (* TODO: don't convert, handle UnknownPtr below *) in let once once_control init_routine = - D.join d (tf_proc var edge prev_node None init_routine [] getl sidel getg sideg d) + let enter = + let d' = S.event man (Events.EnterOnce { once_control; tf = true }) man in + let proc = tf_proc var edge prev_node None init_routine [] getl sidel getg sideg d' in + let rec proc_man = + { man with + ask = (fun (type a) (q: a Queries.t) -> S.query proc_man q); + local = proc; + } + in + S.event proc_man (Events.LeaveOnce { once_control }) proc_man + in + let not_enter = + S.event man (Events.EnterOnce { once_control; tf = false }) man + in + D.join enter not_enter in let one_function f = match f.vtype with From 8fff9a5d9b8c89f2e8d1a0a294a8e0ea64edb86b Mon Sep 17 00:00:00 2001 From: Michael Schwarz Date: Fri, 24 Jan 2025 17:43:27 +0100 Subject: [PATCH 22/68] Onces --- src/analyses/pthreadOnce.ml | 90 ++++++++++++++++++++++++++++ src/framework/constraints.ml | 9 ++- tests/regression/83-once/01-sanity.c | 2 +- 3 files changed, 99 insertions(+), 2 deletions(-) create mode 100644 src/analyses/pthreadOnce.ml diff --git a/src/analyses/pthreadOnce.ml b/src/analyses/pthreadOnce.ml new file mode 100644 index 0000000000..30c7756089 --- /dev/null +++ b/src/analyses/pthreadOnce.ml @@ -0,0 +1,90 @@ +(** Must active and have passed pthreadOnce calls ([pthreadOnce]). *) + +open GoblintCil +open Analyses +module LF = LibraryFunctions + +module Spec = +struct + module Onces = struct + include SetDomain.ToppedSet (CilType.Varinfo) (struct let topname = "All onces" end) + let name () = "mayOnces" + end + + module ActiveOnces = struct + include Lattice.Reverse (Onces) + let name () = "active" + end + + module SeenOnces = struct + include Lattice.Reverse (Onces) + let name () = "seen" + end + + include Analyses.DefaultSpec + + let name () = "pthreadOnce" + module D = Lattice.Prod (ActiveOnces) (SeenOnces) + include Analyses.ValueContexts(D) + + (* transfer functions *) + let assign man (lval:lval) (rval:exp) : D.t = + man.local + + let branch man (exp:exp) (tv:bool) : D.t = + man.local + + let body man (f:fundec) : D.t = + man.local + + let return man (exp:exp option) (f:fundec) : D.t = + man.local + + let enter man (lval: lval option) (f:fundec) (args:exp list) : (D.t * D.t) list = + [man.local, man.local] + + let combine_env man lval fexp f args fc au f_ask = + au + + let combine_assign man (lval:lval option) fexp (f:fundec) (args:exp list) fc (au:D.t) (f_ask: Queries.ask) : D.t = + man.local + + let special man (lval: lval option) (f:varinfo) (arglist:exp list) : D.t = + man.local + + let startstate v = (Onces.empty (), Onces.empty ()) + + let possible_vinfos (a: Queries.ask) barrier = + Queries.AD.to_var_may (a.f (Queries.MayPointTo barrier)) + + let event man (e: Events.t) oman : D.t = + match e with + | Events.EnterOnce { once_control; tf } -> + (let (active, seen) = man.local in + let ask = Analyses.ask_of_man man in + match possible_vinfos ask once_control with + | [v] -> + (Onces.add v active, seen) + | _ -> + man.local) + | Events.LeaveOnce { once_control } -> + (let (active, seen) = man.local in + let ask = Analyses.ask_of_man man in + let active' = Onces.diff active (Onces.of_list (possible_vinfos ask once_control)) in + let seen' = match possible_vinfos ask once_control with + | [v] -> Onces.add v seen + | _ -> seen + in + (active', seen')) + | _ -> man.local + + let threadenter man ~multiple lval f args = + let (_, seen) = man.local in + [Onces.empty (), seen] + + let threadspawn man ~multiple lval f args fman = man.local + let exitstate v = D.top () +end + +let _ = + MCP.register_analysis (module Spec : MCPSpec) diff --git a/src/framework/constraints.ml b/src/framework/constraints.ml index d2c1c8215b..97dffe5d6c 100644 --- a/src/framework/constraints.ml +++ b/src/framework/constraints.ml @@ -271,7 +271,14 @@ struct S.event proc_man (Events.LeaveOnce { once_control }) proc_man in let not_enter = - S.event man (Events.EnterOnce { once_control; tf = false }) man + let d' = S.event man (Events.EnterOnce { once_control; tf = false }) man in + let rec d'_man = + { man with + ask = (fun (type a) (q: a Queries.t) -> S.query d'_man q); + local = d'; + } + in + S.event d'_man (Events.LeaveOnce { once_control }) d'_man in D.join enter not_enter in diff --git a/tests/regression/83-once/01-sanity.c b/tests/regression/83-once/01-sanity.c index 954f70dd4b..3d7875e0c5 100644 --- a/tests/regression/83-once/01-sanity.c +++ b/tests/regression/83-once/01-sanity.c @@ -1,4 +1,4 @@ -// PARAM: --set pre.cppflags[+] "-DGOBLINT_NO_PTHREAD_ONCE" +// PARAM: --set pre.cppflags[+] "-DGOBLINT_NO_PTHREAD_ONCE" --set ana.activated[+] pthreadOnce #include #include From ab0a9dbce376ade09bcaad25e567d16575daa61e Mon Sep 17 00:00:00 2001 From: Michael Schwarz Date: Fri, 24 Jan 2025 18:04:16 +0100 Subject: [PATCH 23/68] Refine --- src/analyses/pthreadOnce.ml | 15 +++++++++++---- src/framework/constraints.ml | 18 +++++++++++------- tests/regression/83-once/01-sanity.c | 7 +++++-- 3 files changed, 27 insertions(+), 13 deletions(-) diff --git a/src/analyses/pthreadOnce.ml b/src/analyses/pthreadOnce.ml index 30c7756089..96877bc485 100644 --- a/src/analyses/pthreadOnce.ml +++ b/src/analyses/pthreadOnce.ml @@ -59,14 +59,21 @@ struct let event man (e: Events.t) oman : D.t = match e with + | Events.EnterOnce { once_control; tf } when tf -> + (let (active, seen) = man.local in + let ask = Analyses.ask_of_man man in + let possible_vinfos = possible_vinfos ask once_control in + let unseen = List.filter (fun v -> not (Onces.mem v seen) && not (Onces.mem v active)) possible_vinfos in + match unseen with + | [] -> raise Deadcode + | [v] -> (Onces.add v active, seen) + | _ :: _ -> man.local) | Events.EnterOnce { once_control; tf } -> (let (active, seen) = man.local in let ask = Analyses.ask_of_man man in match possible_vinfos ask once_control with - | [v] -> - (Onces.add v active, seen) - | _ -> - man.local) + | [v] -> (Onces.add v active, seen) + | _ -> man.local) | Events.LeaveOnce { once_control } -> (let (active, seen) = man.local in let ask = Analyses.ask_of_man man in diff --git a/src/framework/constraints.ml b/src/framework/constraints.ml index 97dffe5d6c..93755e668c 100644 --- a/src/framework/constraints.ml +++ b/src/framework/constraints.ml @@ -262,15 +262,19 @@ struct let enter = let d' = S.event man (Events.EnterOnce { once_control; tf = true }) man in let proc = tf_proc var edge prev_node None init_routine [] getl sidel getg sideg d' in - let rec proc_man = - { man with - ask = (fun (type a) (q: a Queries.t) -> S.query proc_man q); - local = proc; - } - in - S.event proc_man (Events.LeaveOnce { once_control }) proc_man + if not (S.D.is_bot proc) then + let rec proc_man = + { man with + ask = (fun (type a) (q: a Queries.t) -> S.query proc_man q); + local = proc; + } + in + S.event proc_man (Events.LeaveOnce { once_control }) proc_man + else + S.D.bot () in let not_enter = + (* Always possible, will never yield `Bot *) let d' = S.event man (Events.EnterOnce { once_control; tf = false }) man in let rec d'_man = { man with diff --git a/tests/regression/83-once/01-sanity.c b/tests/regression/83-once/01-sanity.c index 3d7875e0c5..7b26a6cbcf 100644 --- a/tests/regression/83-once/01-sanity.c +++ b/tests/regression/83-once/01-sanity.c @@ -17,8 +17,11 @@ int main(void) { pthread_once(&once, fun); pthread_once(&once, fun); - // This fails if the (actual) case that it is not executed twice is ignored. - __goblint_check(g == 1); //TODO + __goblint_check(g < 2); + + if(g = 1) { + __goblint_check(1); //Reachable + } return 0; } From e255c60b92d4861248b0fc75351b4170ac665ea4 Mon Sep 17 00:00:00 2001 From: Michael Schwarz Date: Fri, 24 Jan 2025 18:24:05 +0100 Subject: [PATCH 24/68] Document `pthread_once` --- src/goblint_lib.ml | 1 + 1 file changed, 1 insertion(+) diff --git a/src/goblint_lib.ml b/src/goblint_lib.ml index 415fb21605..1819331d6b 100644 --- a/src/goblint_lib.ml +++ b/src/goblint_lib.ml @@ -130,6 +130,7 @@ module RelationPriv = RelationPriv module ThreadEscape = ThreadEscape module PthreadSignals = PthreadSignals module ExtractPthread = ExtractPthread +module PthreadOnce = PthreadOnce (** {2 Longjmp} From 6df3ff8f4e7a15f033bee709bcbc1f92acc5a42b Mon Sep 17 00:00:00 2001 From: Michael Schwarz Date: Fri, 24 Jan 2025 18:31:05 +0100 Subject: [PATCH 25/68] Add race checking --- src/analyses/pthreadOnce.ml | 12 ++++++++++ tests/regression/83-once/02-normal.c | 34 ++++++++++++++++++++++++++++ 2 files changed, 46 insertions(+) create mode 100644 tests/regression/83-once/02-normal.c diff --git a/src/analyses/pthreadOnce.ml b/src/analyses/pthreadOnce.ml index 96877bc485..fb91fae8f6 100644 --- a/src/analyses/pthreadOnce.ml +++ b/src/analyses/pthreadOnce.ml @@ -85,6 +85,18 @@ struct (active', seen')) | _ -> man.local + let access man _ = man.local + + module A = + struct + include D + let name () = "onces" + let may_race (a1, s1) (a2, s2) = + (Onces.is_empty (Onces.inter a1 (Onces.union a2 s2))) && (Onces.is_empty (Onces.inter a2 (Onces.union a1 s1))) + let should_print f = true + end + + let threadenter man ~multiple lval f args = let (_, seen) = man.local in [Onces.empty (), seen] diff --git a/tests/regression/83-once/02-normal.c b/tests/regression/83-once/02-normal.c new file mode 100644 index 0000000000..bc6cab582d --- /dev/null +++ b/tests/regression/83-once/02-normal.c @@ -0,0 +1,34 @@ +// PARAM: --set pre.cppflags[+] "-DGOBLINT_NO_PTHREAD_ONCE" --set ana.activated[+] pthreadOnce +#include +#include + +int g; +pthread_once_t once = PTHREAD_ONCE_INIT; +pthread_mutex_t mutex1 = PTHREAD_MUTEX_INITIALIZER; + +void fun() { + g = 42; //NORACE +} + + +void *t_fun(void *arg) { + pthread_once(&once, fun); + + pthread_mutex_lock(&mutex1); + g = 10; //NORACE + pthread_mutex_unlock(&mutex1); + return NULL; +} + +int main(void) { + pthread_t id; + pthread_create(&id, NULL, t_fun, NULL); + + pthread_once(&once, fun); + + pthread_mutex_lock(&mutex1); + g = 11; //NORACE + pthread_mutex_unlock(&mutex1); + pthread_join (id, NULL); + return 0; +} From 46d4904d5de9ea0caafc830648ce68350c74ccb1 Mon Sep 17 00:00:00 2001 From: Michael Schwarz Date: Mon, 27 Jan 2025 09:28:42 +0100 Subject: [PATCH 26/68] Add further example --- tests/regression/83-once/03-unknown.c | 44 +++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 tests/regression/83-once/03-unknown.c diff --git a/tests/regression/83-once/03-unknown.c b/tests/regression/83-once/03-unknown.c new file mode 100644 index 0000000000..42c43dab29 --- /dev/null +++ b/tests/regression/83-once/03-unknown.c @@ -0,0 +1,44 @@ +// PARAM: --set pre.cppflags[+] "-DGOBLINT_NO_PTHREAD_ONCE" --set ana.activated[+] pthreadOnce +#include +#include + +int g; +pthread_once_t once1 = PTHREAD_ONCE_INIT; +pthread_once_t once2; // PTHREAD_ONCE_INIT is `0` +pthread_mutex_t mutex1 = PTHREAD_MUTEX_INITIALIZER; + +pthread_once_t *ptr; + +void fun() { + g = 42; //RACE +} + + +void *t_fun(void *arg) { + pthread_once(ptr, fun); + + pthread_mutex_lock(&mutex1); + g = 10; //RACE + pthread_mutex_unlock(&mutex1); + return NULL; +} + +int main(void) { + pthread_t id; + int top; + pthread_create(&id, NULL, t_fun, NULL); + + ptr = &once1; + + if(top) { + ptr = &once2; + } + + pthread_once(ptr, fun); + + pthread_mutex_lock(&mutex1); + g = 11; //RACE + pthread_mutex_unlock(&mutex1); + pthread_join (id, NULL); + return 0; +} From e31ce2ace101f7cb17412ce64e601a0609438cd3 Mon Sep 17 00:00:00 2001 From: Michael Schwarz Date: Mon, 27 Jan 2025 09:30:52 +0100 Subject: [PATCH 27/68] Only print onces in race info if one of the sets is non-empty --- src/analyses/pthreadOnce.ml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/analyses/pthreadOnce.ml b/src/analyses/pthreadOnce.ml index fb91fae8f6..cc7dc3e611 100644 --- a/src/analyses/pthreadOnce.ml +++ b/src/analyses/pthreadOnce.ml @@ -93,7 +93,7 @@ struct let name () = "onces" let may_race (a1, s1) (a2, s2) = (Onces.is_empty (Onces.inter a1 (Onces.union a2 s2))) && (Onces.is_empty (Onces.inter a2 (Onces.union a1 s1))) - let should_print f = true + let should_print (a1, s1) = not (Onces.is_empty a1) || not (Onces.is_empty s1) end From 9dae4045a8c539bc92d99ca1d919b2c36369a7d4 Mon Sep 17 00:00:00 2001 From: Michael Schwarz Date: Mon, 27 Jan 2025 09:56:01 +0100 Subject: [PATCH 28/68] Further test --- tests/regression/83-once/04-thread.c | 58 ++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) create mode 100644 tests/regression/83-once/04-thread.c diff --git a/tests/regression/83-once/04-thread.c b/tests/regression/83-once/04-thread.c new file mode 100644 index 0000000000..c9522040c3 --- /dev/null +++ b/tests/regression/83-once/04-thread.c @@ -0,0 +1,58 @@ +// PARAM: --set pre.cppflags[+] "-DGOBLINT_NO_PTHREAD_ONCE" --set ana.activated[+] pthreadOnce +#include +#include + +int g; +int h; +int i; +pthread_once_t once = PTHREAD_ONCE_INIT; +pthread_once_t i_once = PTHREAD_ONCE_INIT; +pthread_mutex_t mut; + +void *t_other(void* arg) { + g = 17; //RACE + + pthread_mutex_lock(&mut); + i = 7; //NORACE + pthread_mutex_unlock(&mut); +} + +void nesting() { + h = 5; //NORACE +} + +void fun() { + // Even though this is only called inside the once, the accesses in the new thread and the accesses here can happen in parallel + // Checks that active is not passed to the created thread, but seen is passed + pthread_t tid = pthread_create(&tid, NULL, t_other, NULL); + g = 42; //RACE + + h = 8; //NORACE + // Active onces get passed to the callee and back to the caller + nesting(); + h = 12; //NORACE +} + +void ifun() { + i = 11; //NORACE +} + +void *t_fun(void *arg) { + pthread_once(&i_once, ifun); + pthread_once(&once, fun); + return NULL; +} + +int main(void) { + pthread_t id; + int top; + + pthread_create(&id, NULL, t_fun, NULL); + + pthread_once(&i_once, ifun); + pthread_once(&once, fun); + + h = 5; //NORACE + + return 0; +} From 010380e3b2cc53a8b68cf44e97210299d88155e6 Mon Sep 17 00:00:00 2001 From: Michael Schwarz Date: Mon, 27 Jan 2025 10:50:52 +0100 Subject: [PATCH 29/68] Remove workaround for #547 --- conf/bench-yaml-validate.json | 1 - conf/bench-yaml.json | 1 - conf/ldv-races.json | 1 - conf/traces-rel.json | 1 - lib/libc/stub/src/pthread.c | 11 ----------- scripts/sv-comp/archive.sh | 1 - src/maingoblint.ml | 3 --- tests/regression/03-practical/35-base-mutex-macos.t | 2 +- tests/regression/71-doublelocking/07-rec-dyn-osx.c | 3 +-- .../regression/71-doublelocking/20-default-init-osx.c | 2 +- tests/regression/83-once/01-sanity.c | 2 +- tests/regression/83-once/02-normal.c | 2 +- tests/regression/83-once/03-unknown.c | 2 +- tests/regression/83-once/04-thread.c | 2 +- 14 files changed, 7 insertions(+), 27 deletions(-) delete mode 100644 lib/libc/stub/src/pthread.c diff --git a/conf/bench-yaml-validate.json b/conf/bench-yaml-validate.json index 7b18371bd1..2fcdb418da 100644 --- a/conf/bench-yaml-validate.json +++ b/conf/bench-yaml-validate.json @@ -71,7 +71,6 @@ }, "pre": { "cppflags": [ - "-DGOBLINT_NO_PTHREAD_ONCE", "-DGOBLINT_NO_QSORT", "-DGOBLINT_NO_BSEARCH" ] diff --git a/conf/bench-yaml.json b/conf/bench-yaml.json index fd97b2c08c..52f0b33347 100644 --- a/conf/bench-yaml.json +++ b/conf/bench-yaml.json @@ -67,7 +67,6 @@ }, "pre": { "cppflags": [ - "-DGOBLINT_NO_PTHREAD_ONCE", "-DGOBLINT_NO_QSORT", "-DGOBLINT_NO_BSEARCH" ] diff --git a/conf/ldv-races.json b/conf/ldv-races.json index a06a6da610..da8355c7e8 100644 --- a/conf/ldv-races.json +++ b/conf/ldv-races.json @@ -1,7 +1,6 @@ { "pre": { "cppflags": [ - "-DGOBLINT_NO_PTHREAD_ONCE", "-DGOBLINT_NO_QSORT", "-DGOBLINT_NO_BSEARCH" ] diff --git a/conf/traces-rel.json b/conf/traces-rel.json index 2b82a57554..fafb397a7f 100644 --- a/conf/traces-rel.json +++ b/conf/traces-rel.json @@ -83,7 +83,6 @@ }, "pre": { "cppflags": [ - "-DGOBLINT_NO_PTHREAD_ONCE", "-DGOBLINT_NO_QSORT", "-DGOBLINT_NO_BSEARCH" ] diff --git a/lib/libc/stub/src/pthread.c b/lib/libc/stub/src/pthread.c deleted file mode 100644 index 1de6202b4b..0000000000 --- a/lib/libc/stub/src/pthread.c +++ /dev/null @@ -1,11 +0,0 @@ -#ifndef GOBLINT_NO_PTHREAD_ONCE -#include - -int pthread_once(pthread_once_t *once_control,void (*init_routine)(void)) __attribute__((goblint_stub)); -int pthread_once(pthread_once_t *once_control,void (*init_routine)(void)) { - // Not actually once, just call it - int top; - init_routine(); - return top; -} -#endif diff --git a/scripts/sv-comp/archive.sh b/scripts/sv-comp/archive.sh index aefac8f769..33ea1b4368 100755 --- a/scripts/sv-comp/archive.sh +++ b/scripts/sv-comp/archive.sh @@ -37,7 +37,6 @@ zip goblint/scripts/sv-comp/goblint.zip \ goblint/lib/libc/stub/include/assert.h \ goblint/lib/goblint/runtime/include/goblint.h \ goblint/lib/libc/stub/src/stdlib.c \ - goblint/lib/libc/stub/src/pthread.c \ goblint/lib/sv-comp/stub/src/sv-comp.c \ goblint/README.md \ goblint/LICENSE diff --git a/src/maingoblint.ml b/src/maingoblint.ml index cb81ea0b86..c3f1d0f9ea 100644 --- a/src/maingoblint.ml +++ b/src/maingoblint.ml @@ -418,9 +418,6 @@ let preprocess_files () = if List.mem "c" (get_string_list "lib.activated") then extra_files := find_custom_include (Fpath.v "stdlib.c") :: !extra_files; - if List.mem "pthread" (get_string_list "lib.activated") then - extra_files := find_custom_include (Fpath.v "pthread.c") :: !extra_files; - if List.mem "sv-comp" (get_string_list "lib.activated") then extra_files := find_custom_include (Fpath.v "sv-comp.c") :: !extra_files; diff --git a/tests/regression/03-practical/35-base-mutex-macos.t b/tests/regression/03-practical/35-base-mutex-macos.t index 1d8a184d4c..929d03eb5b 100644 --- a/tests/regression/03-practical/35-base-mutex-macos.t +++ b/tests/regression/03-practical/35-base-mutex-macos.t @@ -1,4 +1,4 @@ - $ goblint --enable witness.yaml.enabled --disable witness.invariant.accessed --set pre.cppflags[+] -DGOBLINT_NO_PTHREAD_ONCE 35-base-mutex-macos.c + $ goblint --enable witness.yaml.enabled --disable witness.invariant.accessed 35-base-mutex-macos.c [Info][Deadcode] Logical lines of code (LLoC) summary: live: 2 dead: 0 diff --git a/tests/regression/71-doublelocking/07-rec-dyn-osx.c b/tests/regression/71-doublelocking/07-rec-dyn-osx.c index bb3cf65657..4059356371 100644 --- a/tests/regression/71-doublelocking/07-rec-dyn-osx.c +++ b/tests/regression/71-doublelocking/07-rec-dyn-osx.c @@ -1,6 +1,5 @@ -// PARAM: --set ana.activated[+] 'maylocks' --set ana.activated[+] 'pthreadMutexType' --set pre.cppflags[+] "-DGOBLINT_NO_PTHREAD_ONCE" +// PARAM: --set ana.activated[+] 'maylocks' --set ana.activated[+] 'pthreadMutexType' // Here, we do not include pthread.h, so MutexAttr.recursive_int remains at `2`, emulating the behavior of OS X. -#define GOBLINT_NO_PTHREAD_ONCE 1 typedef signed char __int8_t; typedef unsigned char __uint8_t; typedef short __int16_t; diff --git a/tests/regression/71-doublelocking/20-default-init-osx.c b/tests/regression/71-doublelocking/20-default-init-osx.c index 4d3ec1f8d7..eaa6ec58be 100644 --- a/tests/regression/71-doublelocking/20-default-init-osx.c +++ b/tests/regression/71-doublelocking/20-default-init-osx.c @@ -1,4 +1,4 @@ -// PARAM: --set ana.activated[+] 'maylocks' --set ana.activated[+] 'pthreadMutexType' --set pre.cppflags[+] "-DGOBLINT_NO_PTHREAD_ONCE" +// PARAM: --set ana.activated[+] 'maylocks' --set ana.activated[+] 'pthreadMutexType' // Here, we do not include pthread.h, to emulate the behavior of OS X. #define NULL ((void *)0) typedef signed char __int8_t; diff --git a/tests/regression/83-once/01-sanity.c b/tests/regression/83-once/01-sanity.c index 7b26a6cbcf..8a26012571 100644 --- a/tests/regression/83-once/01-sanity.c +++ b/tests/regression/83-once/01-sanity.c @@ -1,4 +1,4 @@ -// PARAM: --set pre.cppflags[+] "-DGOBLINT_NO_PTHREAD_ONCE" --set ana.activated[+] pthreadOnce +// PARAM: --set ana.activated[+] pthreadOnce #include #include diff --git a/tests/regression/83-once/02-normal.c b/tests/regression/83-once/02-normal.c index bc6cab582d..ee10a7d6b4 100644 --- a/tests/regression/83-once/02-normal.c +++ b/tests/regression/83-once/02-normal.c @@ -1,4 +1,4 @@ -// PARAM: --set pre.cppflags[+] "-DGOBLINT_NO_PTHREAD_ONCE" --set ana.activated[+] pthreadOnce +// PARAM: --set ana.activated[+] pthreadOnce #include #include diff --git a/tests/regression/83-once/03-unknown.c b/tests/regression/83-once/03-unknown.c index 42c43dab29..16cb2c5a12 100644 --- a/tests/regression/83-once/03-unknown.c +++ b/tests/regression/83-once/03-unknown.c @@ -1,4 +1,4 @@ -// PARAM: --set pre.cppflags[+] "-DGOBLINT_NO_PTHREAD_ONCE" --set ana.activated[+] pthreadOnce +// PARAM: --set ana.activated[+] pthreadOnce #include #include diff --git a/tests/regression/83-once/04-thread.c b/tests/regression/83-once/04-thread.c index c9522040c3..c467bacc22 100644 --- a/tests/regression/83-once/04-thread.c +++ b/tests/regression/83-once/04-thread.c @@ -1,4 +1,4 @@ -// PARAM: --set pre.cppflags[+] "-DGOBLINT_NO_PTHREAD_ONCE" --set ana.activated[+] pthreadOnce +// PARAM: --set ana.activated[+] pthreadOnce #include #include From aa6850912076728e8b31708d0c6359bab575d39e Mon Sep 17 00:00:00 2001 From: Michael Schwarz Date: Wed, 29 Jan 2025 11:11:17 +0100 Subject: [PATCH 30/68] Use Seq instead of constructing from scratch --- src/analyses/pthreadBarriers.ml | 29 ++++++++++++++++++++--------- src/domain/disjointDomain.ml | 2 ++ src/domain/setDomain.ml | 8 ++++++++ 3 files changed, 30 insertions(+), 9 deletions(-) diff --git a/src/analyses/pthreadBarriers.ml b/src/analyses/pthreadBarriers.ml index 1cea151fed..cc51c163c6 100644 --- a/src/analyses/pthreadBarriers.ml +++ b/src/analyses/pthreadBarriers.ml @@ -52,6 +52,19 @@ struct Queries.AD.to_var_may (a.f (Queries.MayPointTo barrier)) let special man (lval: lval option) (f:varinfo) (arglist:exp list) : D.t = + let exists_k pred k waiters = + let k_product elems = + let rec doit k = + if k = 1 then + Seq.map (Seq.return) elems + else + let arg = doit (k-1) in + Seq.map_product (Seq.cons) elems arg + in + doit k + in + Seq.exists pred (k_product (Waiters.to_seq waiters)) + in let desc = LF.find f in match desc.special arglist with | BarrierWait barrier -> @@ -88,16 +101,14 @@ struct let must = let waiters = Waiters.elements relevant_waiters in let min_cap = Z.to_int min_cap in - let lists = List.init (min_cap - 1) (fun _ -> waiters) in - let candidates = BatList.n_cartesian_product lists in - let can_proceed = List.exists (fun candidate -> - let rec do_it = function - | [] -> true - | x::xs -> List.for_all (fun y -> MHPplusLock.mhp x y) xs && do_it xs - in - do_it candidate - ) candidates + let can_proceed_pred seq = + let rec doit seq = match Seq.uncons seq with + | None -> true + | Some (h, t) -> Seq.for_all (MHPplusLock.mhp h) t && doit t + in + doit seq in + let can_proceed = exists_k can_proceed_pred (min_cap - 1) relevant_waiters in if not can_proceed then raise Analyses.Deadcode; (* limit to this case to avoid having to construct all permutations above *) if BatList.compare_length_with waiters (min_cap - 1) = 0 then diff --git a/src/domain/disjointDomain.ml b/src/domain/disjointDomain.ml index 3e02c1d3a0..35a730a4d5 100644 --- a/src/domain/disjointDomain.ml +++ b/src/domain/disjointDomain.ml @@ -117,6 +117,7 @@ struct add e acc ) (empty ()) es let elements m = fold List.cons m [] (* no intermediate per-bucket lists *) + let to_seq m = fold Seq.cons m Seq.empty let map f m = fold (fun e acc -> add (f e) acc ) m (empty ()) (* no intermediate lists *) @@ -323,6 +324,7 @@ struct add e acc ) (empty ()) es let elements m = fold List.cons m [] (* no intermediate per-bucket lists *) + let to_seq m = fold Seq.cons m Seq.empty let map f s = fold (fun e acc -> add (f e) acc ) s (empty ()) (* no intermediate lists *) diff --git a/src/domain/setDomain.ml b/src/domain/setDomain.ml index c552363f3d..e11c8182de 100644 --- a/src/domain/setDomain.ml +++ b/src/domain/setDomain.ml @@ -95,6 +95,12 @@ sig On set abstractions this lists only canonical elements, not all subsumed elements. *) + val to_seq: t -> elt Seq.t + (** See {!Set.S.to_seq}. + + On set abstractions this lists only canonical elements, + not all subsumed elements. *) + val of_list: elt list -> t val min_elt: t -> elt @@ -332,6 +338,7 @@ struct let exists f = schema_default true (S.exists f) let filter f = schema (fun t -> `Lifted (S.filter f t)) "filter on `Top" let elements = schema S.elements "elements on `Top" + let to_seq = schema S.to_seq "to_seq on `Top" let of_list xs = `Lifted (S.of_list xs) let cardinal = schema S.cardinal "cardinal on `Top" let min_elt = schema S.min_elt "min_elt on `Top" @@ -471,6 +478,7 @@ struct let mem e e' = E.leq e e' let choose e = e let elements e = [e] + let to_seq e = Seq.return e let remove e e' = if E.leq e' e then E.bot () (* NB! strong removal *) From 31323cd214123f40f3eac63a33a72298a84d2c73 Mon Sep 17 00:00:00 2001 From: Michael Schwarz Date: Thu, 30 Jan 2025 10:53:48 +0100 Subject: [PATCH 31/68] Add switch to not use mutexes in race detection --- src/analyses/mutexAnalysis.ml | 2 ++ src/config/options.schema.json | 13 +++++++++++++ 2 files changed, 15 insertions(+) diff --git a/src/analyses/mutexAnalysis.ml b/src/analyses/mutexAnalysis.ml index c712ca9644..996eca9954 100644 --- a/src/analyses/mutexAnalysis.ml +++ b/src/analyses/mutexAnalysis.ml @@ -267,6 +267,8 @@ struct include MustLocksetRW let name () = "lock" let may_race ls1 ls2 = + let use_lockset = GobConfig.get_bool "ana.race.digests.lockset" in + (not use_lockset) || (* not mutually exclusive *) not @@ exists (fun ((m1, w1) as l1) -> if w1 then diff --git a/src/config/options.schema.json b/src/config/options.schema.json index 39c863ad49..a2aa7b8feb 100644 --- a/src/config/options.schema.json +++ b/src/config/options.schema.json @@ -1105,6 +1105,19 @@ "description": "Report races for volatile variables.", "type": "boolean", "default": true + }, + "digests": { + "title": "ana.race.digests", + "type" : "object", + "properties" : { + "lockset" : { + "title": "ana.race.digests.lockset", + "description": "Use lockset digest for excluding data races.", + "type" : "boolean", + "default" : true + } + }, + "additionalProperties": false } }, "additionalProperties": false From d9bd9cadaec38dbe6f5b5a75d767864a968a2fbe Mon Sep 17 00:00:00 2001 From: Michael Schwarz Date: Thu, 30 Jan 2025 11:28:50 +0100 Subject: [PATCH 32/68] Add option to disable thread digest --- src/analyses/threadId.ml | 5 ++++- src/config/options.schema.json | 6 ++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/analyses/threadId.ml b/src/analyses/threadId.ml index 53d070a056..d9724b2c2e 100644 --- a/src/analyses/threadId.ml +++ b/src/analyses/threadId.ml @@ -132,7 +132,10 @@ struct struct include Printable.Option (ThreadLifted) (struct let name = "nonunique" end) let name () = "thread" - let may_race (t1: t) (t2: t) = match t1, t2 with + let may_race (t1: t) (t2: t) = + let use_tid = GobConfig.get_bool "ana.race.digests.thread" in + (not use_tid) || + match t1, t2 with | Some t1, Some t2 when ThreadLifted.equal t1 t2 -> false (* only unique threads *) | _, _ -> true let should_print = Option.is_some diff --git a/src/config/options.schema.json b/src/config/options.schema.json index a2aa7b8feb..ecda257c92 100644 --- a/src/config/options.schema.json +++ b/src/config/options.schema.json @@ -1115,6 +1115,12 @@ "description": "Use lockset digest for excluding data races.", "type" : "boolean", "default" : true + }, + "thread" : { + "title": "ana.race.digests.thread", + "description": "TODO! How does relate to the MHP one? Seems to hit only in one case", + "type" : "boolean", + "default" : true } }, "additionalProperties": false From 164e0c9ec341129755ffd644122592e9812bca84 Mon Sep 17 00:00:00 2001 From: Michael Schwarz Date: Thu, 30 Jan 2025 11:42:51 +0100 Subject: [PATCH 33/68] Add option for freshness --- src/analyses/mallocFresh.ml | 4 +++- src/config/options.schema.json | 6 ++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/analyses/mallocFresh.ml b/src/analyses/mallocFresh.ml index c226d7e6ce..4e7bd84571 100644 --- a/src/analyses/mallocFresh.ml +++ b/src/analyses/mallocFresh.ml @@ -64,7 +64,9 @@ struct struct include BoolDomain.Bool let name () = "fresh" - let may_race f1 f2 = not (f1 || f2) + let may_race f1 f2 = + let use_fresh = GobConfig.get_bool "ana.race.digests.fresh" in + (not use_fresh) || not (f1 || f2) let should_print f = f end let access man (a: Queries.access) = diff --git a/src/config/options.schema.json b/src/config/options.schema.json index ecda257c92..07d6bf974f 100644 --- a/src/config/options.schema.json +++ b/src/config/options.schema.json @@ -1121,6 +1121,12 @@ "description": "TODO! How does relate to the MHP one? Seems to hit only in one case", "type" : "boolean", "default" : true + }, + "fresh" : { + "title": "ana.race.digests.fresh", + "description": "Use freshness analysis for excluding data races.", + "type" : "boolean", + "default" : true } }, "additionalProperties": false From 7ae5e0798b650160e46c9e209f3d98f0e875b4bc Mon Sep 17 00:00:00 2001 From: Michael Schwarz Date: Thu, 30 Jan 2025 11:47:41 +0100 Subject: [PATCH 34/68] Add toggle for region / symbLocks --- src/analyses/region.ml | 5 ++++- src/analyses/symbLocks.ml | 4 +++- src/config/options.schema.json | 12 ++++++++++++ 3 files changed, 19 insertions(+), 2 deletions(-) diff --git a/src/analyses/region.ml b/src/analyses/region.ml index 0fb61059e2..d02df20d0d 100644 --- a/src/analyses/region.ml +++ b/src/analyses/region.ml @@ -64,7 +64,10 @@ struct struct include Printable.Option (Lvals) (struct let name = "no region" end) let name () = "region" - let may_race r1 r2 = match r1, r2 with + let may_race r1 r2 = + let use_region = GobConfig.get_bool "ana.race.digests.region" in + (not use_region) || + match r1, r2 with | None, _ | _, None -> false (* TODO: Should it happen in the first place that RegMap has empty value? Happens in 09-regions/34-escape_rc *) diff --git a/src/analyses/symbLocks.ml b/src/analyses/symbLocks.ml index 0850fac317..9cf212b6b9 100644 --- a/src/analyses/symbLocks.ml +++ b/src/analyses/symbLocks.ml @@ -121,7 +121,9 @@ struct include SetDomain.Make (E) let name () = "symblock" - let may_race lp lp2 = disjoint lp lp2 + let may_race lp lp2 = + let use_symblocks = GobConfig.get_bool "ana.race.digests.symb_locks" in + (not use_symblocks) || disjoint lp lp2 let should_print lp = not (is_empty lp) end diff --git a/src/config/options.schema.json b/src/config/options.schema.json index 07d6bf974f..e27e89ab92 100644 --- a/src/config/options.schema.json +++ b/src/config/options.schema.json @@ -1127,6 +1127,18 @@ "description": "Use freshness analysis for excluding data races.", "type" : "boolean", "default" : true + }, + "region" : { + "title": "ana.race.digests.region", + "description": "Use region analysis for excluding data races.", + "type" : "boolean", + "default" : true + }, + "symb_locks" : { + "title": "ana.race.digests.symb_locks", + "description": "Use symb_locks analysis for excluding data races.", + "type" : "boolean", + "default" : true } }, "additionalProperties": false From 1273af27c33c1e42a7707c543df00e789ad6fb8d Mon Sep 17 00:00:00 2001 From: Michael Schwarz Date: Fri, 31 Jan 2025 14:10:38 +0100 Subject: [PATCH 35/68] Thread flag option --- src/analyses/threadFlag.ml | 4 +++- src/config/options.schema.json | 6 ++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/analyses/threadFlag.ml b/src/analyses/threadFlag.ml index 1e0ff7db9f..454ea28961 100644 --- a/src/analyses/threadFlag.ml +++ b/src/analyses/threadFlag.ml @@ -56,7 +56,9 @@ struct struct include BoolDomain.Bool let name () = "multi" - let may_race m1 m2 = m1 && m2 (* kill access when single threaded *) + let may_race m1 m2 = + let use_threadflag = GobConfig.get_bool "ana.race.digests.threadflag" in + (not use_threadflag) || (m1 && m2) (* kill access when single threaded *) let should_print m = not m end let access man _ = diff --git a/src/config/options.schema.json b/src/config/options.schema.json index e27e89ab92..808f11eaa8 100644 --- a/src/config/options.schema.json +++ b/src/config/options.schema.json @@ -1139,6 +1139,12 @@ "description": "Use symb_locks analysis for excluding data races.", "type" : "boolean", "default" : true + }, + "threadflag" : { + "title": "ana.race.digests.threadflag", + "description": "Use threadflag analysis for excluding data races.", + "type" : "boolean", + "default" : true } }, "additionalProperties": false From aa976793a9b847521a204f9ce05ffa13a96f45a6 Mon Sep 17 00:00:00 2001 From: Michael Schwarz Date: Fri, 31 Jan 2025 14:16:51 +0100 Subject: [PATCH 36/68] Add `tid` and `joins` digest --- src/cdomains/mHP.ml | 12 +++++++----- src/config/options.schema.json | 12 ++++++++++++ 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/src/cdomains/mHP.ml b/src/cdomains/mHP.ml index afaf6d67e3..18aa1719fd 100644 --- a/src/cdomains/mHP.ml +++ b/src/cdomains/mHP.ml @@ -77,17 +77,19 @@ let must_be_joined other joined = (** May two program points with respective MHP information happen in parallel *) let may_happen_in_parallel one two = - let {tid=tid; created=created; must_joined=must_joined} = one in + let use_tid = GobConfig.get_bool "ana.race.digests.tid" in + let use_join = GobConfig.get_bool "ana.race.digests.join" in + let {tid; created; must_joined} = one in let {tid=tid2; created=created2; must_joined=must_joined2} = two in match tid,tid2 with | `Lifted tid, `Lifted tid2 -> - if (TID.is_unique tid) && (TID.equal tid tid2) then + if use_tid && (TID.is_unique tid) && (TID.equal tid tid2) then false - else if definitely_not_started (tid,created) tid2 || definitely_not_started (tid2,created2) tid then + else if use_tid && (definitely_not_started (tid,created) tid2 || definitely_not_started (tid2,created2) tid) then false - else if must_be_joined tid2 must_joined || must_be_joined tid must_joined2 then + else if use_tid && use_join && (must_be_joined tid2 must_joined || must_be_joined tid must_joined2) then false - else if exists_definitely_not_started_in_joined (tid,created) must_joined2 || exists_definitely_not_started_in_joined (tid2,created2) must_joined then + else if use_tid && use_join && (exists_definitely_not_started_in_joined (tid,created) must_joined2 || exists_definitely_not_started_in_joined (tid2,created2) must_joined) then false else true diff --git a/src/config/options.schema.json b/src/config/options.schema.json index 808f11eaa8..6bcab0d253 100644 --- a/src/config/options.schema.json +++ b/src/config/options.schema.json @@ -1145,6 +1145,18 @@ "description": "Use threadflag analysis for excluding data races.", "type" : "boolean", "default" : true + }, + "tid" : { + "title": "ana.race.digests.tid", + "description": "Use tid analysis for excluding data races.", + "type" : "boolean", + "default" : true + }, + "join" : { + "title": "ana.race.digests.join", + "description": "Use join analysis for excluding data races.", + "type" : "boolean", + "default" : true } }, "additionalProperties": false From 4c2d8a38cafeb41214db369ad384fbbfb0f6459f Mon Sep 17 00:00:00 2001 From: Michael Schwarz Date: Fri, 31 Jan 2025 14:35:49 +0100 Subject: [PATCH 37/68] Add configs for experiments --- conf/race-digests/full.json | 118 ++++++++++++++++++++++++ conf/race-digests/mutex-only.json | 128 ++++++++++++++++++++++++++ conf/race-digests/none.json | 128 ++++++++++++++++++++++++++ conf/race-digests/tid+mutex+join.json | 128 ++++++++++++++++++++++++++ conf/race-digests/tid+mutex.json | 128 ++++++++++++++++++++++++++ conf/race-digests/tid-only.json | 128 ++++++++++++++++++++++++++ 6 files changed, 758 insertions(+) create mode 100644 conf/race-digests/full.json create mode 100644 conf/race-digests/mutex-only.json create mode 100644 conf/race-digests/none.json create mode 100644 conf/race-digests/tid+mutex+join.json create mode 100644 conf/race-digests/tid+mutex.json create mode 100644 conf/race-digests/tid-only.json diff --git a/conf/race-digests/full.json b/conf/race-digests/full.json new file mode 100644 index 0000000000..dedc393ba1 --- /dev/null +++ b/conf/race-digests/full.json @@ -0,0 +1,118 @@ +{ + "ana": { + "sv-comp": { + "enabled": true, + "functions": true + }, + "int": { + "def_exc": true, + "enums": false, + "interval": true + }, + "float": { + "interval": true, + "evaluate_math_functions": true + }, + "activated": [ + "base", + "threadid", + "threadflag", + "threadreturn", + "mallocWrapper", + "mutexEvents", + "mutex", + "access", + "race", + "escape", + "expRelation", + "mhp", + "assert", + "var_eq", + "symb_locks", + "region", + "thread", + "threadJoins", + "abortUnless" + ], + "path_sens": [ + "mutex", + "malloc_null", + "uninit", + "expsplit", + "activeSetjmp", + "memLeak", + "threadflag" + ], + "context": { + "widen": false + }, + "base": { + "arrays": { + "domain": "partitioned" + } + }, + "race": { + "free": false, + "call": false + }, + "autotune": { + "enabled": true, + "activated": [ + "singleThreaded", + "mallocWrappers", + "noRecursiveIntervals", + "enums", + "congruence", + "octagon", + "wideningThresholds", + "loopUnrollHeuristic", + "memsafetySpecification", + "noOverflows", + "termination", + "tmpSpecialAnalysis" + ] + } + }, + "exp": { + "region-offsets": true + }, + "solver": "td3", + "sem": { + "unknown_function": { + "spawn": false + }, + "int": { + "signed_overflow": "assume_none" + }, + "null-pointer": { + "dereference": "assume_none" + } + }, + "witness": { + "graphml": { + "enabled": true, + "id": "enumerate", + "unknown": false + }, + "yaml": { + "enabled": true, + "format-version": "2.0", + "entry-types": [ + "invariant_set" + ], + "invariant-types": [ + "loop_invariant" + ] + }, + "invariant": { + "loop-head": true, + "after-lock": false, + "other": false, + "accessed": false, + "exact": true + } + }, + "pre": { + "enabled": false + } +} diff --git a/conf/race-digests/mutex-only.json b/conf/race-digests/mutex-only.json new file mode 100644 index 0000000000..864dfeb9be --- /dev/null +++ b/conf/race-digests/mutex-only.json @@ -0,0 +1,128 @@ +{ + "ana": { + "sv-comp": { + "enabled": true, + "functions": true + }, + "int": { + "def_exc": true, + "enums": false, + "interval": true + }, + "float": { + "interval": true, + "evaluate_math_functions": true + }, + "activated": [ + "base", + "threadid", + "threadflag", + "threadreturn", + "mallocWrapper", + "mutexEvents", + "mutex", + "access", + "race", + "escape", + "expRelation", + "mhp", + "assert", + "var_eq", + "symb_locks", + "region", + "thread", + "threadJoins", + "abortUnless" + ], + "path_sens": [ + "mutex", + "malloc_null", + "uninit", + "expsplit", + "activeSetjmp", + "memLeak", + "threadflag" + ], + "context": { + "widen": false + }, + "base": { + "arrays": { + "domain": "partitioned" + } + }, + "race": { + "free": false, + "call": false, + "digests": { + "lockset": true, + "thread": false, + "fresh": false, + "region": false, + "symb_locks": false, + "threadflag": false, + "tid": false, + "join" : false + } + }, + "autotune": { + "enabled": true, + "activated": [ + "singleThreaded", + "mallocWrappers", + "noRecursiveIntervals", + "enums", + "congruence", + "octagon", + "wideningThresholds", + "loopUnrollHeuristic", + "memsafetySpecification", + "noOverflows", + "termination", + "tmpSpecialAnalysis" + ] + } + }, + "exp": { + "region-offsets": true + }, + "solver": "td3", + "sem": { + "unknown_function": { + "spawn": false + }, + "int": { + "signed_overflow": "assume_none" + }, + "null-pointer": { + "dereference": "assume_none" + } + }, + "witness": { + "graphml": { + "enabled": true, + "id": "enumerate", + "unknown": false + }, + "yaml": { + "enabled": true, + "format-version": "2.0", + "entry-types": [ + "invariant_set" + ], + "invariant-types": [ + "loop_invariant" + ] + }, + "invariant": { + "loop-head": true, + "after-lock": false, + "other": false, + "accessed": false, + "exact": true + } + }, + "pre": { + "enabled": false + } +} diff --git a/conf/race-digests/none.json b/conf/race-digests/none.json new file mode 100644 index 0000000000..533e0b8a0d --- /dev/null +++ b/conf/race-digests/none.json @@ -0,0 +1,128 @@ +{ + "ana": { + "sv-comp": { + "enabled": true, + "functions": true + }, + "int": { + "def_exc": true, + "enums": false, + "interval": true + }, + "float": { + "interval": true, + "evaluate_math_functions": true + }, + "activated": [ + "base", + "threadid", + "threadflag", + "threadreturn", + "mallocWrapper", + "mutexEvents", + "mutex", + "access", + "race", + "escape", + "expRelation", + "mhp", + "assert", + "var_eq", + "symb_locks", + "region", + "thread", + "threadJoins", + "abortUnless" + ], + "path_sens": [ + "mutex", + "malloc_null", + "uninit", + "expsplit", + "activeSetjmp", + "memLeak", + "threadflag" + ], + "context": { + "widen": false + }, + "base": { + "arrays": { + "domain": "partitioned" + } + }, + "race": { + "free": false, + "call": false, + "digests": { + "lockset": false, + "thread": false, + "fresh": false, + "region": false, + "symb_locks": false, + "threadflag": false, + "tid": false, + "join" : false + } + }, + "autotune": { + "enabled": true, + "activated": [ + "singleThreaded", + "mallocWrappers", + "noRecursiveIntervals", + "enums", + "congruence", + "octagon", + "wideningThresholds", + "loopUnrollHeuristic", + "memsafetySpecification", + "noOverflows", + "termination", + "tmpSpecialAnalysis" + ] + } + }, + "exp": { + "region-offsets": true + }, + "solver": "td3", + "sem": { + "unknown_function": { + "spawn": false + }, + "int": { + "signed_overflow": "assume_none" + }, + "null-pointer": { + "dereference": "assume_none" + } + }, + "witness": { + "graphml": { + "enabled": true, + "id": "enumerate", + "unknown": false + }, + "yaml": { + "enabled": true, + "format-version": "2.0", + "entry-types": [ + "invariant_set" + ], + "invariant-types": [ + "loop_invariant" + ] + }, + "invariant": { + "loop-head": true, + "after-lock": false, + "other": false, + "accessed": false, + "exact": true + } + }, + "pre": { + "enabled": false + } +} diff --git a/conf/race-digests/tid+mutex+join.json b/conf/race-digests/tid+mutex+join.json new file mode 100644 index 0000000000..d24fd6603a --- /dev/null +++ b/conf/race-digests/tid+mutex+join.json @@ -0,0 +1,128 @@ +{ + "ana": { + "sv-comp": { + "enabled": true, + "functions": true + }, + "int": { + "def_exc": true, + "enums": false, + "interval": true + }, + "float": { + "interval": true, + "evaluate_math_functions": true + }, + "activated": [ + "base", + "threadid", + "threadflag", + "threadreturn", + "mallocWrapper", + "mutexEvents", + "mutex", + "access", + "race", + "escape", + "expRelation", + "mhp", + "assert", + "var_eq", + "symb_locks", + "region", + "thread", + "threadJoins", + "abortUnless" + ], + "path_sens": [ + "mutex", + "malloc_null", + "uninit", + "expsplit", + "activeSetjmp", + "memLeak", + "threadflag" + ], + "context": { + "widen": false + }, + "base": { + "arrays": { + "domain": "partitioned" + } + }, + "race": { + "free": false, + "call": false, + "digests": { + "lockset": true, + "thread": false, + "fresh": false, + "region": false, + "symb_locks": false, + "threadflag": false, + "tid": true, + "join" : true + } + }, + "autotune": { + "enabled": true, + "activated": [ + "singleThreaded", + "mallocWrappers", + "noRecursiveIntervals", + "enums", + "congruence", + "octagon", + "wideningThresholds", + "loopUnrollHeuristic", + "memsafetySpecification", + "noOverflows", + "termination", + "tmpSpecialAnalysis" + ] + } + }, + "exp": { + "region-offsets": true + }, + "solver": "td3", + "sem": { + "unknown_function": { + "spawn": false + }, + "int": { + "signed_overflow": "assume_none" + }, + "null-pointer": { + "dereference": "assume_none" + } + }, + "witness": { + "graphml": { + "enabled": true, + "id": "enumerate", + "unknown": false + }, + "yaml": { + "enabled": true, + "format-version": "2.0", + "entry-types": [ + "invariant_set" + ], + "invariant-types": [ + "loop_invariant" + ] + }, + "invariant": { + "loop-head": true, + "after-lock": false, + "other": false, + "accessed": false, + "exact": true + } + }, + "pre": { + "enabled": false + } +} diff --git a/conf/race-digests/tid+mutex.json b/conf/race-digests/tid+mutex.json new file mode 100644 index 0000000000..98e4732913 --- /dev/null +++ b/conf/race-digests/tid+mutex.json @@ -0,0 +1,128 @@ +{ + "ana": { + "sv-comp": { + "enabled": true, + "functions": true + }, + "int": { + "def_exc": true, + "enums": false, + "interval": true + }, + "float": { + "interval": true, + "evaluate_math_functions": true + }, + "activated": [ + "base", + "threadid", + "threadflag", + "threadreturn", + "mallocWrapper", + "mutexEvents", + "mutex", + "access", + "race", + "escape", + "expRelation", + "mhp", + "assert", + "var_eq", + "symb_locks", + "region", + "thread", + "threadJoins", + "abortUnless" + ], + "path_sens": [ + "mutex", + "malloc_null", + "uninit", + "expsplit", + "activeSetjmp", + "memLeak", + "threadflag" + ], + "context": { + "widen": false + }, + "base": { + "arrays": { + "domain": "partitioned" + } + }, + "race": { + "free": false, + "call": false, + "digests": { + "lockset": true, + "thread": false, + "fresh": false, + "region": false, + "symb_locks": false, + "threadflag": false, + "tid": true, + "join" : false + } + }, + "autotune": { + "enabled": true, + "activated": [ + "singleThreaded", + "mallocWrappers", + "noRecursiveIntervals", + "enums", + "congruence", + "octagon", + "wideningThresholds", + "loopUnrollHeuristic", + "memsafetySpecification", + "noOverflows", + "termination", + "tmpSpecialAnalysis" + ] + } + }, + "exp": { + "region-offsets": true + }, + "solver": "td3", + "sem": { + "unknown_function": { + "spawn": false + }, + "int": { + "signed_overflow": "assume_none" + }, + "null-pointer": { + "dereference": "assume_none" + } + }, + "witness": { + "graphml": { + "enabled": true, + "id": "enumerate", + "unknown": false + }, + "yaml": { + "enabled": true, + "format-version": "2.0", + "entry-types": [ + "invariant_set" + ], + "invariant-types": [ + "loop_invariant" + ] + }, + "invariant": { + "loop-head": true, + "after-lock": false, + "other": false, + "accessed": false, + "exact": true + } + }, + "pre": { + "enabled": false + } +} diff --git a/conf/race-digests/tid-only.json b/conf/race-digests/tid-only.json new file mode 100644 index 0000000000..90acc8fd5a --- /dev/null +++ b/conf/race-digests/tid-only.json @@ -0,0 +1,128 @@ +{ + "ana": { + "sv-comp": { + "enabled": true, + "functions": true + }, + "int": { + "def_exc": true, + "enums": false, + "interval": true + }, + "float": { + "interval": true, + "evaluate_math_functions": true + }, + "activated": [ + "base", + "threadid", + "threadflag", + "threadreturn", + "mallocWrapper", + "mutexEvents", + "mutex", + "access", + "race", + "escape", + "expRelation", + "mhp", + "assert", + "var_eq", + "symb_locks", + "region", + "thread", + "threadJoins", + "abortUnless" + ], + "path_sens": [ + "mutex", + "malloc_null", + "uninit", + "expsplit", + "activeSetjmp", + "memLeak", + "threadflag" + ], + "context": { + "widen": false + }, + "base": { + "arrays": { + "domain": "partitioned" + } + }, + "race": { + "free": false, + "call": false, + "digests": { + "lockset": false, + "thread": false, + "fresh": false, + "region": false, + "symb_locks": false, + "threadflag": false, + "tid": true, + "join" : false + } + }, + "autotune": { + "enabled": true, + "activated": [ + "singleThreaded", + "mallocWrappers", + "noRecursiveIntervals", + "enums", + "congruence", + "octagon", + "wideningThresholds", + "loopUnrollHeuristic", + "memsafetySpecification", + "noOverflows", + "termination", + "tmpSpecialAnalysis" + ] + } + }, + "exp": { + "region-offsets": true + }, + "solver": "td3", + "sem": { + "unknown_function": { + "spawn": false + }, + "int": { + "signed_overflow": "assume_none" + }, + "null-pointer": { + "dereference": "assume_none" + } + }, + "witness": { + "graphml": { + "enabled": true, + "id": "enumerate", + "unknown": false + }, + "yaml": { + "enabled": true, + "format-version": "2.0", + "entry-types": [ + "invariant_set" + ], + "invariant-types": [ + "loop_invariant" + ] + }, + "invariant": { + "loop-head": true, + "after-lock": false, + "other": false, + "accessed": false, + "exact": true + } + }, + "pre": { + "enabled": false + } +} From cea4416735bea146ae3722366dbd0bb50f1d5fc8 Mon Sep 17 00:00:00 2001 From: Michael Schwarz Date: Fri, 31 Jan 2025 17:40:33 +0100 Subject: [PATCH 38/68] Add two more configs --- conf/race-digests/full-minus-region.json | 128 +++++++++++++++++++++++ conf/race-digests/mutex+threadflag.json | 128 +++++++++++++++++++++++ 2 files changed, 256 insertions(+) create mode 100644 conf/race-digests/full-minus-region.json create mode 100644 conf/race-digests/mutex+threadflag.json diff --git a/conf/race-digests/full-minus-region.json b/conf/race-digests/full-minus-region.json new file mode 100644 index 0000000000..ed045fa6f2 --- /dev/null +++ b/conf/race-digests/full-minus-region.json @@ -0,0 +1,128 @@ +{ + "ana": { + "sv-comp": { + "enabled": true, + "functions": true + }, + "int": { + "def_exc": true, + "enums": false, + "interval": true + }, + "float": { + "interval": true, + "evaluate_math_functions": true + }, + "activated": [ + "base", + "threadid", + "threadflag", + "threadreturn", + "mallocWrapper", + "mutexEvents", + "mutex", + "access", + "race", + "escape", + "expRelation", + "mhp", + "assert", + "var_eq", + "symb_locks", + "region", + "thread", + "threadJoins", + "abortUnless" + ], + "path_sens": [ + "mutex", + "malloc_null", + "uninit", + "expsplit", + "activeSetjmp", + "memLeak", + "threadflag" + ], + "context": { + "widen": false + }, + "base": { + "arrays": { + "domain": "partitioned" + } + }, + "race": { + "free": false, + "call": false, + "digests": { + "lockset": true, + "thread": true, + "fresh": true, + "region": false, + "symb_locks": true, + "threadflag": true, + "tid": true, + "join" : true + } + }, + "autotune": { + "enabled": true, + "activated": [ + "singleThreaded", + "mallocWrappers", + "noRecursiveIntervals", + "enums", + "congruence", + "octagon", + "wideningThresholds", + "loopUnrollHeuristic", + "memsafetySpecification", + "noOverflows", + "termination", + "tmpSpecialAnalysis" + ] + } + }, + "exp": { + "region-offsets": true + }, + "solver": "td3", + "sem": { + "unknown_function": { + "spawn": false + }, + "int": { + "signed_overflow": "assume_none" + }, + "null-pointer": { + "dereference": "assume_none" + } + }, + "witness": { + "graphml": { + "enabled": true, + "id": "enumerate", + "unknown": false + }, + "yaml": { + "enabled": true, + "format-version": "2.0", + "entry-types": [ + "invariant_set" + ], + "invariant-types": [ + "loop_invariant" + ] + }, + "invariant": { + "loop-head": true, + "after-lock": false, + "other": false, + "accessed": false, + "exact": true + } + }, + "pre": { + "enabled": false + } +} diff --git a/conf/race-digests/mutex+threadflag.json b/conf/race-digests/mutex+threadflag.json new file mode 100644 index 0000000000..2e0049736c --- /dev/null +++ b/conf/race-digests/mutex+threadflag.json @@ -0,0 +1,128 @@ +{ + "ana": { + "sv-comp": { + "enabled": true, + "functions": true + }, + "int": { + "def_exc": true, + "enums": false, + "interval": true + }, + "float": { + "interval": true, + "evaluate_math_functions": true + }, + "activated": [ + "base", + "threadid", + "threadflag", + "threadreturn", + "mallocWrapper", + "mutexEvents", + "mutex", + "access", + "race", + "escape", + "expRelation", + "mhp", + "assert", + "var_eq", + "symb_locks", + "region", + "thread", + "threadJoins", + "abortUnless" + ], + "path_sens": [ + "mutex", + "malloc_null", + "uninit", + "expsplit", + "activeSetjmp", + "memLeak", + "threadflag" + ], + "context": { + "widen": false + }, + "base": { + "arrays": { + "domain": "partitioned" + } + }, + "race": { + "free": false, + "call": false, + "digests": { + "lockset": true, + "thread": false, + "fresh": false, + "region": false, + "symb_locks": false, + "threadflag": true, + "tid": false, + "join" : false + } + }, + "autotune": { + "enabled": true, + "activated": [ + "singleThreaded", + "mallocWrappers", + "noRecursiveIntervals", + "enums", + "congruence", + "octagon", + "wideningThresholds", + "loopUnrollHeuristic", + "memsafetySpecification", + "noOverflows", + "termination", + "tmpSpecialAnalysis" + ] + } + }, + "exp": { + "region-offsets": true + }, + "solver": "td3", + "sem": { + "unknown_function": { + "spawn": false + }, + "int": { + "signed_overflow": "assume_none" + }, + "null-pointer": { + "dereference": "assume_none" + } + }, + "witness": { + "graphml": { + "enabled": true, + "id": "enumerate", + "unknown": false + }, + "yaml": { + "enabled": true, + "format-version": "2.0", + "entry-types": [ + "invariant_set" + ], + "invariant-types": [ + "loop_invariant" + ] + }, + "invariant": { + "loop-head": true, + "after-lock": false, + "other": false, + "accessed": false, + "exact": true + } + }, + "pre": { + "enabled": false + } +} From 4f10b6e0bfbec99afb53fa03439cda8a7c08b1ff Mon Sep 17 00:00:00 2001 From: Michael Schwarz Date: Mon, 19 May 2025 16:11:21 +0200 Subject: [PATCH 39/68] Add full+once+barrier --- conf/race-digests/full+once+barrier.json | 120 +++++++++++++++++++++++ 1 file changed, 120 insertions(+) create mode 100644 conf/race-digests/full+once+barrier.json diff --git a/conf/race-digests/full+once+barrier.json b/conf/race-digests/full+once+barrier.json new file mode 100644 index 0000000000..70ca39b92b --- /dev/null +++ b/conf/race-digests/full+once+barrier.json @@ -0,0 +1,120 @@ +{ + "ana": { + "sv-comp": { + "enabled": true, + "functions": true + }, + "int": { + "def_exc": true, + "enums": false, + "interval": true + }, + "float": { + "interval": true, + "evaluate_math_functions": true + }, + "activated": [ + "base", + "threadid", + "threadflag", + "threadreturn", + "mallocWrapper", + "mutexEvents", + "mutex", + "access", + "race", + "escape", + "expRelation", + "mhp", + "assert", + "var_eq", + "symb_locks", + "region", + "thread", + "threadJoins", + "abortUnless", + "pthreadBarriers", + "pthreadOnce" + ], + "path_sens": [ + "mutex", + "malloc_null", + "uninit", + "expsplit", + "activeSetjmp", + "memLeak", + "threadflag" + ], + "context": { + "widen": false + }, + "base": { + "arrays": { + "domain": "partitioned" + } + }, + "race": { + "free": false, + "call": false + }, + "autotune": { + "enabled": true, + "activated": [ + "singleThreaded", + "mallocWrappers", + "noRecursiveIntervals", + "enums", + "congruence", + "octagon", + "wideningThresholds", + "loopUnrollHeuristic", + "memsafetySpecification", + "noOverflows", + "termination", + "tmpSpecialAnalysis" + ] + } + }, + "exp": { + "region-offsets": true + }, + "solver": "td3", + "sem": { + "unknown_function": { + "spawn": false + }, + "int": { + "signed_overflow": "assume_none" + }, + "null-pointer": { + "dereference": "assume_none" + } + }, + "witness": { + "graphml": { + "enabled": true, + "id": "enumerate", + "unknown": false + }, + "yaml": { + "enabled": true, + "format-version": "2.0", + "entry-types": [ + "invariant_set" + ], + "invariant-types": [ + "loop_invariant" + ] + }, + "invariant": { + "loop-head": true, + "after-lock": false, + "other": false, + "accessed": false, + "exact": true + } + }, + "pre": { + "enabled": false + } +} From e461572d98d13331223d4a965b406647a212902e Mon Sep 17 00:00:00 2001 From: Michael Schwarz Date: Tue, 20 May 2025 17:18:36 +0200 Subject: [PATCH 40/68] Add tid+thread --- conf/race-digests/tid+thread.json | 128 ++++++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 conf/race-digests/tid+thread.json diff --git a/conf/race-digests/tid+thread.json b/conf/race-digests/tid+thread.json new file mode 100644 index 0000000000..bd4dea95b7 --- /dev/null +++ b/conf/race-digests/tid+thread.json @@ -0,0 +1,128 @@ +{ + "ana": { + "sv-comp": { + "enabled": true, + "functions": true + }, + "int": { + "def_exc": true, + "enums": false, + "interval": true + }, + "float": { + "interval": true, + "evaluate_math_functions": true + }, + "activated": [ + "base", + "threadid", + "threadflag", + "threadreturn", + "mallocWrapper", + "mutexEvents", + "mutex", + "access", + "race", + "escape", + "expRelation", + "mhp", + "assert", + "var_eq", + "symb_locks", + "region", + "thread", + "threadJoins", + "abortUnless" + ], + "path_sens": [ + "mutex", + "malloc_null", + "uninit", + "expsplit", + "activeSetjmp", + "memLeak", + "threadflag" + ], + "context": { + "widen": false + }, + "base": { + "arrays": { + "domain": "partitioned" + } + }, + "race": { + "free": false, + "call": false, + "digests": { + "lockset": false, + "thread": true, + "fresh": false, + "region": false, + "symb_locks": false, + "threadflag": false, + "tid": true, + "join" : false + } + }, + "autotune": { + "enabled": true, + "activated": [ + "singleThreaded", + "mallocWrappers", + "noRecursiveIntervals", + "enums", + "congruence", + "octagon", + "wideningThresholds", + "loopUnrollHeuristic", + "memsafetySpecification", + "noOverflows", + "termination", + "tmpSpecialAnalysis" + ] + } + }, + "exp": { + "region-offsets": true + }, + "solver": "td3", + "sem": { + "unknown_function": { + "spawn": false + }, + "int": { + "signed_overflow": "assume_none" + }, + "null-pointer": { + "dereference": "assume_none" + } + }, + "witness": { + "graphml": { + "enabled": true, + "id": "enumerate", + "unknown": false + }, + "yaml": { + "enabled": true, + "format-version": "2.0", + "entry-types": [ + "invariant_set" + ], + "invariant-types": [ + "loop_invariant" + ] + }, + "invariant": { + "loop-head": true, + "after-lock": false, + "other": false, + "accessed": false, + "exact": true + } + }, + "pre": { + "enabled": false + } +} From b8a9baf555b560311d478a675a3398b64ea92f87 Mon Sep 17 00:00:00 2001 From: Michael Schwarz Date: Wed, 21 May 2025 17:28:14 +0200 Subject: [PATCH 41/68] Add tf-only config --- conf/race-digests/tf-only.json | 128 +++++++++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 conf/race-digests/tf-only.json diff --git a/conf/race-digests/tf-only.json b/conf/race-digests/tf-only.json new file mode 100644 index 0000000000..b5f977047c --- /dev/null +++ b/conf/race-digests/tf-only.json @@ -0,0 +1,128 @@ +{ + "ana": { + "sv-comp": { + "enabled": true, + "functions": true + }, + "int": { + "def_exc": true, + "enums": false, + "interval": true + }, + "float": { + "interval": true, + "evaluate_math_functions": true + }, + "activated": [ + "base", + "threadid", + "threadflag", + "threadreturn", + "mallocWrapper", + "mutexEvents", + "mutex", + "access", + "race", + "escape", + "expRelation", + "mhp", + "assert", + "var_eq", + "symb_locks", + "region", + "thread", + "threadJoins", + "abortUnless" + ], + "path_sens": [ + "mutex", + "malloc_null", + "uninit", + "expsplit", + "activeSetjmp", + "memLeak", + "threadflag" + ], + "context": { + "widen": false + }, + "base": { + "arrays": { + "domain": "partitioned" + } + }, + "race": { + "free": false, + "call": false, + "digests": { + "lockset": false, + "thread": false, + "fresh": false, + "region": false, + "symb_locks": false, + "threadflag": true, + "tid": false, + "join" : false + } + }, + "autotune": { + "enabled": true, + "activated": [ + "singleThreaded", + "mallocWrappers", + "noRecursiveIntervals", + "enums", + "congruence", + "octagon", + "wideningThresholds", + "loopUnrollHeuristic", + "memsafetySpecification", + "noOverflows", + "termination", + "tmpSpecialAnalysis" + ] + } + }, + "exp": { + "region-offsets": true + }, + "solver": "td3", + "sem": { + "unknown_function": { + "spawn": false + }, + "int": { + "signed_overflow": "assume_none" + }, + "null-pointer": { + "dereference": "assume_none" + } + }, + "witness": { + "graphml": { + "enabled": true, + "id": "enumerate", + "unknown": false + }, + "yaml": { + "enabled": true, + "format-version": "2.0", + "entry-types": [ + "invariant_set" + ], + "invariant-types": [ + "loop_invariant" + ] + }, + "invariant": { + "loop-head": true, + "after-lock": false, + "other": false, + "accessed": false, + "exact": true + } + }, + "pre": { + "enabled": false + } +} From db51b7e600840d90b14caed3220b2f9d747f64c6 Mon Sep 17 00:00:00 2001 From: Michael Schwarz Date: Wed, 21 May 2025 18:01:26 +0200 Subject: [PATCH 42/68] tf+thread --- conf/race-digests/tf+thread.json | 128 +++++++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 conf/race-digests/tf+thread.json diff --git a/conf/race-digests/tf+thread.json b/conf/race-digests/tf+thread.json new file mode 100644 index 0000000000..fadeea8e25 --- /dev/null +++ b/conf/race-digests/tf+thread.json @@ -0,0 +1,128 @@ +{ + "ana": { + "sv-comp": { + "enabled": true, + "functions": true + }, + "int": { + "def_exc": true, + "enums": false, + "interval": true + }, + "float": { + "interval": true, + "evaluate_math_functions": true + }, + "activated": [ + "base", + "threadid", + "threadflag", + "threadreturn", + "mallocWrapper", + "mutexEvents", + "mutex", + "access", + "race", + "escape", + "expRelation", + "mhp", + "assert", + "var_eq", + "symb_locks", + "region", + "thread", + "threadJoins", + "abortUnless" + ], + "path_sens": [ + "mutex", + "malloc_null", + "uninit", + "expsplit", + "activeSetjmp", + "memLeak", + "threadflag" + ], + "context": { + "widen": false + }, + "base": { + "arrays": { + "domain": "partitioned" + } + }, + "race": { + "free": false, + "call": false, + "digests": { + "lockset": false, + "thread": true, + "fresh": false, + "region": false, + "symb_locks": false, + "threadflag": true, + "tid": false, + "join" : false + } + }, + "autotune": { + "enabled": true, + "activated": [ + "singleThreaded", + "mallocWrappers", + "noRecursiveIntervals", + "enums", + "congruence", + "octagon", + "wideningThresholds", + "loopUnrollHeuristic", + "memsafetySpecification", + "noOverflows", + "termination", + "tmpSpecialAnalysis" + ] + } + }, + "exp": { + "region-offsets": true + }, + "solver": "td3", + "sem": { + "unknown_function": { + "spawn": false + }, + "int": { + "signed_overflow": "assume_none" + }, + "null-pointer": { + "dereference": "assume_none" + } + }, + "witness": { + "graphml": { + "enabled": true, + "id": "enumerate", + "unknown": false + }, + "yaml": { + "enabled": true, + "format-version": "2.0", + "entry-types": [ + "invariant_set" + ], + "invariant-types": [ + "loop_invariant" + ] + }, + "invariant": { + "loop-head": true, + "after-lock": false, + "other": false, + "accessed": false, + "exact": true + } + }, + "pre": { + "enabled": false + } +} From 00ba5a2a2cb9b6bd8deafce96a66d351db53ddd4 Mon Sep 17 00:00:00 2001 From: Michael Schwarz Date: Wed, 21 May 2025 18:17:03 +0200 Subject: [PATCH 43/68] Always emit singel-threaded --- src/analyses/accessAnalysis.ml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/analyses/accessAnalysis.ml b/src/analyses/accessAnalysis.ml index 55d79a1131..4c2741ac4a 100644 --- a/src/analyses/accessAnalysis.ml +++ b/src/analyses/accessAnalysis.ml @@ -28,8 +28,7 @@ struct let init _ = collect_local := get_bool "witness.yaml.enabled" && get_bool "witness.invariant.accessed"; - let activated = get_string_list "ana.activated" in - emit_single_threaded := List.mem (ModifiedSinceSetjmp.Spec.name ()) activated || List.mem (PoisonVariables.Spec.name ()) activated + emit_single_threaded := true let do_access (man: (D.t, G.t, C.t, V.t) man) (kind:AccessKind.t) (reach:bool) (e:exp) = if M.tracing then M.trace "access" "do_access %a %a %B" d_exp e AccessKind.pretty kind reach; From c22f20b6d5f54ad132db3c026ae15a4db1a8c07e Mon Sep 17 00:00:00 2001 From: Michael Schwarz Date: Thu, 22 May 2025 14:14:23 +0200 Subject: [PATCH 44/68] Add new configs --- conf/race-digests/fresh-only.json | 128 ++++++++++++++++++++++++++ conf/race-digests/region-only.json | 128 ++++++++++++++++++++++++++ conf/race-digests/symblocks-only.json | 128 ++++++++++++++++++++++++++ 3 files changed, 384 insertions(+) create mode 100644 conf/race-digests/fresh-only.json create mode 100644 conf/race-digests/region-only.json create mode 100644 conf/race-digests/symblocks-only.json diff --git a/conf/race-digests/fresh-only.json b/conf/race-digests/fresh-only.json new file mode 100644 index 0000000000..86bc6d93e2 --- /dev/null +++ b/conf/race-digests/fresh-only.json @@ -0,0 +1,128 @@ +{ + "ana": { + "sv-comp": { + "enabled": true, + "functions": true + }, + "int": { + "def_exc": true, + "enums": false, + "interval": true + }, + "float": { + "interval": true, + "evaluate_math_functions": true + }, + "activated": [ + "base", + "threadid", + "threadflag", + "threadreturn", + "mallocWrapper", + "mutexEvents", + "mutex", + "access", + "race", + "escape", + "expRelation", + "mhp", + "assert", + "var_eq", + "symb_locks", + "region", + "thread", + "threadJoins", + "abortUnless" + ], + "path_sens": [ + "mutex", + "malloc_null", + "uninit", + "expsplit", + "activeSetjmp", + "memLeak", + "threadflag" + ], + "context": { + "widen": false + }, + "base": { + "arrays": { + "domain": "partitioned" + } + }, + "race": { + "free": false, + "call": false, + "digests": { + "lockset": false, + "thread": false, + "fresh": true, + "region": false, + "symb_locks": false, + "threadflag": false, + "tid": false, + "join" : false + } + }, + "autotune": { + "enabled": true, + "activated": [ + "singleThreaded", + "mallocWrappers", + "noRecursiveIntervals", + "enums", + "congruence", + "octagon", + "wideningThresholds", + "loopUnrollHeuristic", + "memsafetySpecification", + "noOverflows", + "termination", + "tmpSpecialAnalysis" + ] + } + }, + "exp": { + "region-offsets": true + }, + "solver": "td3", + "sem": { + "unknown_function": { + "spawn": false + }, + "int": { + "signed_overflow": "assume_none" + }, + "null-pointer": { + "dereference": "assume_none" + } + }, + "witness": { + "graphml": { + "enabled": true, + "id": "enumerate", + "unknown": false + }, + "yaml": { + "enabled": true, + "format-version": "2.0", + "entry-types": [ + "invariant_set" + ], + "invariant-types": [ + "loop_invariant" + ] + }, + "invariant": { + "loop-head": true, + "after-lock": false, + "other": false, + "accessed": false, + "exact": true + } + }, + "pre": { + "enabled": false + } +} diff --git a/conf/race-digests/region-only.json b/conf/race-digests/region-only.json new file mode 100644 index 0000000000..c9bdfb40b0 --- /dev/null +++ b/conf/race-digests/region-only.json @@ -0,0 +1,128 @@ +{ + "ana": { + "sv-comp": { + "enabled": true, + "functions": true + }, + "int": { + "def_exc": true, + "enums": false, + "interval": true + }, + "float": { + "interval": true, + "evaluate_math_functions": true + }, + "activated": [ + "base", + "threadid", + "threadflag", + "threadreturn", + "mallocWrapper", + "mutexEvents", + "mutex", + "access", + "race", + "escape", + "expRelation", + "mhp", + "assert", + "var_eq", + "symb_locks", + "region", + "thread", + "threadJoins", + "abortUnless" + ], + "path_sens": [ + "mutex", + "malloc_null", + "uninit", + "expsplit", + "activeSetjmp", + "memLeak", + "threadflag" + ], + "context": { + "widen": false + }, + "base": { + "arrays": { + "domain": "partitioned" + } + }, + "race": { + "free": false, + "call": false, + "digests": { + "lockset": false, + "thread": false, + "fresh": false, + "region": true, + "symb_locks": false, + "threadflag": false, + "tid": false, + "join" : false + } + }, + "autotune": { + "enabled": true, + "activated": [ + "singleThreaded", + "mallocWrappers", + "noRecursiveIntervals", + "enums", + "congruence", + "octagon", + "wideningThresholds", + "loopUnrollHeuristic", + "memsafetySpecification", + "noOverflows", + "termination", + "tmpSpecialAnalysis" + ] + } + }, + "exp": { + "region-offsets": true + }, + "solver": "td3", + "sem": { + "unknown_function": { + "spawn": false + }, + "int": { + "signed_overflow": "assume_none" + }, + "null-pointer": { + "dereference": "assume_none" + } + }, + "witness": { + "graphml": { + "enabled": true, + "id": "enumerate", + "unknown": false + }, + "yaml": { + "enabled": true, + "format-version": "2.0", + "entry-types": [ + "invariant_set" + ], + "invariant-types": [ + "loop_invariant" + ] + }, + "invariant": { + "loop-head": true, + "after-lock": false, + "other": false, + "accessed": false, + "exact": true + } + }, + "pre": { + "enabled": false + } +} diff --git a/conf/race-digests/symblocks-only.json b/conf/race-digests/symblocks-only.json new file mode 100644 index 0000000000..41428e9a35 --- /dev/null +++ b/conf/race-digests/symblocks-only.json @@ -0,0 +1,128 @@ +{ + "ana": { + "sv-comp": { + "enabled": true, + "functions": true + }, + "int": { + "def_exc": true, + "enums": false, + "interval": true + }, + "float": { + "interval": true, + "evaluate_math_functions": true + }, + "activated": [ + "base", + "threadid", + "threadflag", + "threadreturn", + "mallocWrapper", + "mutexEvents", + "mutex", + "access", + "race", + "escape", + "expRelation", + "mhp", + "assert", + "var_eq", + "symb_locks", + "region", + "thread", + "threadJoins", + "abortUnless" + ], + "path_sens": [ + "mutex", + "malloc_null", + "uninit", + "expsplit", + "activeSetjmp", + "memLeak", + "threadflag" + ], + "context": { + "widen": false + }, + "base": { + "arrays": { + "domain": "partitioned" + } + }, + "race": { + "free": false, + "call": false, + "digests": { + "lockset": false, + "thread": false, + "fresh": false, + "region": false, + "symb_locks": true, + "threadflag": false, + "tid": false, + "join" : false + } + }, + "autotune": { + "enabled": true, + "activated": [ + "singleThreaded", + "mallocWrappers", + "noRecursiveIntervals", + "enums", + "congruence", + "octagon", + "wideningThresholds", + "loopUnrollHeuristic", + "memsafetySpecification", + "noOverflows", + "termination", + "tmpSpecialAnalysis" + ] + } + }, + "exp": { + "region-offsets": true + }, + "solver": "td3", + "sem": { + "unknown_function": { + "spawn": false + }, + "int": { + "signed_overflow": "assume_none" + }, + "null-pointer": { + "dereference": "assume_none" + } + }, + "witness": { + "graphml": { + "enabled": true, + "id": "enumerate", + "unknown": false + }, + "yaml": { + "enabled": true, + "format-version": "2.0", + "entry-types": [ + "invariant_set" + ], + "invariant-types": [ + "loop_invariant" + ] + }, + "invariant": { + "loop-head": true, + "after-lock": false, + "other": false, + "accessed": false, + "exact": true + } + }, + "pre": { + "enabled": false + } +} From 69cc287007388f6f7ab49021846e2ad609b4f034 Mon Sep 17 00:00:00 2001 From: Michael Schwarz Date: Thu, 22 May 2025 16:53:57 +0200 Subject: [PATCH 45/68] Add config --- .../full-minus-region+symblocks.json | 128 ++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 conf/race-digests/full-minus-region+symblocks.json diff --git a/conf/race-digests/full-minus-region+symblocks.json b/conf/race-digests/full-minus-region+symblocks.json new file mode 100644 index 0000000000..fcfafb6d61 --- /dev/null +++ b/conf/race-digests/full-minus-region+symblocks.json @@ -0,0 +1,128 @@ +{ + "ana": { + "sv-comp": { + "enabled": true, + "functions": true + }, + "int": { + "def_exc": true, + "enums": false, + "interval": true + }, + "float": { + "interval": true, + "evaluate_math_functions": true + }, + "activated": [ + "base", + "threadid", + "threadflag", + "threadreturn", + "mallocWrapper", + "mutexEvents", + "mutex", + "access", + "race", + "escape", + "expRelation", + "mhp", + "assert", + "var_eq", + "symb_locks", + "region", + "thread", + "threadJoins", + "abortUnless" + ], + "path_sens": [ + "mutex", + "malloc_null", + "uninit", + "expsplit", + "activeSetjmp", + "memLeak", + "threadflag" + ], + "context": { + "widen": false + }, + "base": { + "arrays": { + "domain": "partitioned" + } + }, + "race": { + "free": false, + "call": false, + "digests": { + "lockset": true, + "thread": true, + "fresh": true, + "region": false, + "symb_locks": false, + "threadflag": true, + "tid": true, + "join" : true + } + }, + "autotune": { + "enabled": true, + "activated": [ + "singleThreaded", + "mallocWrappers", + "noRecursiveIntervals", + "enums", + "congruence", + "octagon", + "wideningThresholds", + "loopUnrollHeuristic", + "memsafetySpecification", + "noOverflows", + "termination", + "tmpSpecialAnalysis" + ] + } + }, + "exp": { + "region-offsets": true + }, + "solver": "td3", + "sem": { + "unknown_function": { + "spawn": false + }, + "int": { + "signed_overflow": "assume_none" + }, + "null-pointer": { + "dereference": "assume_none" + } + }, + "witness": { + "graphml": { + "enabled": true, + "id": "enumerate", + "unknown": false + }, + "yaml": { + "enabled": true, + "format-version": "2.0", + "entry-types": [ + "invariant_set" + ], + "invariant-types": [ + "loop_invariant" + ] + }, + "invariant": { + "loop-head": true, + "after-lock": false, + "other": false, + "accessed": false, + "exact": true + } + }, + "pre": { + "enabled": false + } +} From 96d1dab1758b57f4cc738c2e16599e9edd8b2a3c Mon Sep 17 00:00:00 2001 From: Michael Schwarz Date: Tue, 27 May 2025 15:52:10 +0200 Subject: [PATCH 46/68] Always record accesses for race checking --- src/analyses/raceAnalysis.ml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/analyses/raceAnalysis.ml b/src/analyses/raceAnalysis.ml index 263506b4fb..c1ca2e97b9 100644 --- a/src/analyses/raceAnalysis.ml +++ b/src/analyses/raceAnalysis.ml @@ -304,7 +304,7 @@ struct let event man e oman = match e with - | Events.Access {exp; ad; kind; reach} when ThreadFlag.is_currently_multi (Analyses.ask_of_man man) -> (* threadflag query in post-threadspawn man *) + | Events.Access {exp; ad; kind; reach} when true (* ThreadFlag.is_currently_multi (Analyses.ask_of_man man) *) -> (* threadflag query in post-threadspawn man *) (* must use original (pre-assign, etc) man queries *) let conf = 110 in let module AD = Queries.AD in From a84150722a089a20a55fadf1f3490e251e0d05eb Mon Sep 17 00:00:00 2001 From: Michael Schwarz Date: Wed, 28 May 2025 17:21:00 +0200 Subject: [PATCH 47/68] Remove thread --- conf/race-digests/fresh-only.json | 1 - .../full-minus-region+symblocks.json | 1 - conf/race-digests/full-minus-region.json | 1 - conf/race-digests/mutex+threadflag.json | 3 +- conf/race-digests/mutex-only.json | 1 - conf/race-digests/none.json | 1 - conf/race-digests/region-only.json | 2 +- conf/race-digests/symblocks-only.json | 2 +- conf/race-digests/tf+thread.json | 128 ------------------ conf/race-digests/tf-only.json | 2 +- conf/race-digests/tid+mutex+join.json | 2 +- conf/race-digests/tid+mutex.json | 2 +- conf/race-digests/tid+thread.json | 128 ------------------ conf/race-digests/tid-only.json | 2 +- src/analyses/threadFlag.ml | 27 +++- src/analyses/threadId.ml | 2 +- src/config/options.schema.json | 6 - 17 files changed, 29 insertions(+), 282 deletions(-) delete mode 100644 conf/race-digests/tf+thread.json delete mode 100644 conf/race-digests/tid+thread.json diff --git a/conf/race-digests/fresh-only.json b/conf/race-digests/fresh-only.json index 86bc6d93e2..9f2cafd408 100644 --- a/conf/race-digests/fresh-only.json +++ b/conf/race-digests/fresh-only.json @@ -56,7 +56,6 @@ "call": false, "digests": { "lockset": false, - "thread": false, "fresh": true, "region": false, "symb_locks": false, diff --git a/conf/race-digests/full-minus-region+symblocks.json b/conf/race-digests/full-minus-region+symblocks.json index fcfafb6d61..0f7093a867 100644 --- a/conf/race-digests/full-minus-region+symblocks.json +++ b/conf/race-digests/full-minus-region+symblocks.json @@ -56,7 +56,6 @@ "call": false, "digests": { "lockset": true, - "thread": true, "fresh": true, "region": false, "symb_locks": false, diff --git a/conf/race-digests/full-minus-region.json b/conf/race-digests/full-minus-region.json index ed045fa6f2..afb1b4048c 100644 --- a/conf/race-digests/full-minus-region.json +++ b/conf/race-digests/full-minus-region.json @@ -56,7 +56,6 @@ "call": false, "digests": { "lockset": true, - "thread": true, "fresh": true, "region": false, "symb_locks": true, diff --git a/conf/race-digests/mutex+threadflag.json b/conf/race-digests/mutex+threadflag.json index 2e0049736c..9bed592781 100644 --- a/conf/race-digests/mutex+threadflag.json +++ b/conf/race-digests/mutex+threadflag.json @@ -56,8 +56,7 @@ "call": false, "digests": { "lockset": true, - "thread": false, - "fresh": false, + "region": false, "symb_locks": false, "threadflag": true, diff --git a/conf/race-digests/mutex-only.json b/conf/race-digests/mutex-only.json index 864dfeb9be..a23e3bf546 100644 --- a/conf/race-digests/mutex-only.json +++ b/conf/race-digests/mutex-only.json @@ -56,7 +56,6 @@ "call": false, "digests": { "lockset": true, - "thread": false, "fresh": false, "region": false, "symb_locks": false, diff --git a/conf/race-digests/none.json b/conf/race-digests/none.json index 533e0b8a0d..93b82cc39a 100644 --- a/conf/race-digests/none.json +++ b/conf/race-digests/none.json @@ -56,7 +56,6 @@ "call": false, "digests": { "lockset": false, - "thread": false, "fresh": false, "region": false, "symb_locks": false, diff --git a/conf/race-digests/region-only.json b/conf/race-digests/region-only.json index c9bdfb40b0..e202197269 100644 --- a/conf/race-digests/region-only.json +++ b/conf/race-digests/region-only.json @@ -56,7 +56,7 @@ "call": false, "digests": { "lockset": false, - "thread": false, + "fresh": false, "region": true, "symb_locks": false, diff --git a/conf/race-digests/symblocks-only.json b/conf/race-digests/symblocks-only.json index 41428e9a35..e3a3ce6a06 100644 --- a/conf/race-digests/symblocks-only.json +++ b/conf/race-digests/symblocks-only.json @@ -56,7 +56,7 @@ "call": false, "digests": { "lockset": false, - "thread": false, + "fresh": false, "region": false, "symb_locks": true, diff --git a/conf/race-digests/tf+thread.json b/conf/race-digests/tf+thread.json deleted file mode 100644 index fadeea8e25..0000000000 --- a/conf/race-digests/tf+thread.json +++ /dev/null @@ -1,128 +0,0 @@ -{ - "ana": { - "sv-comp": { - "enabled": true, - "functions": true - }, - "int": { - "def_exc": true, - "enums": false, - "interval": true - }, - "float": { - "interval": true, - "evaluate_math_functions": true - }, - "activated": [ - "base", - "threadid", - "threadflag", - "threadreturn", - "mallocWrapper", - "mutexEvents", - "mutex", - "access", - "race", - "escape", - "expRelation", - "mhp", - "assert", - "var_eq", - "symb_locks", - "region", - "thread", - "threadJoins", - "abortUnless" - ], - "path_sens": [ - "mutex", - "malloc_null", - "uninit", - "expsplit", - "activeSetjmp", - "memLeak", - "threadflag" - ], - "context": { - "widen": false - }, - "base": { - "arrays": { - "domain": "partitioned" - } - }, - "race": { - "free": false, - "call": false, - "digests": { - "lockset": false, - "thread": true, - "fresh": false, - "region": false, - "symb_locks": false, - "threadflag": true, - "tid": false, - "join" : false - } - }, - "autotune": { - "enabled": true, - "activated": [ - "singleThreaded", - "mallocWrappers", - "noRecursiveIntervals", - "enums", - "congruence", - "octagon", - "wideningThresholds", - "loopUnrollHeuristic", - "memsafetySpecification", - "noOverflows", - "termination", - "tmpSpecialAnalysis" - ] - } - }, - "exp": { - "region-offsets": true - }, - "solver": "td3", - "sem": { - "unknown_function": { - "spawn": false - }, - "int": { - "signed_overflow": "assume_none" - }, - "null-pointer": { - "dereference": "assume_none" - } - }, - "witness": { - "graphml": { - "enabled": true, - "id": "enumerate", - "unknown": false - }, - "yaml": { - "enabled": true, - "format-version": "2.0", - "entry-types": [ - "invariant_set" - ], - "invariant-types": [ - "loop_invariant" - ] - }, - "invariant": { - "loop-head": true, - "after-lock": false, - "other": false, - "accessed": false, - "exact": true - } - }, - "pre": { - "enabled": false - } -} diff --git a/conf/race-digests/tf-only.json b/conf/race-digests/tf-only.json index b5f977047c..f87f076c03 100644 --- a/conf/race-digests/tf-only.json +++ b/conf/race-digests/tf-only.json @@ -56,7 +56,7 @@ "call": false, "digests": { "lockset": false, - "thread": false, + "fresh": false, "region": false, "symb_locks": false, diff --git a/conf/race-digests/tid+mutex+join.json b/conf/race-digests/tid+mutex+join.json index d24fd6603a..e32d35f73c 100644 --- a/conf/race-digests/tid+mutex+join.json +++ b/conf/race-digests/tid+mutex+join.json @@ -56,7 +56,7 @@ "call": false, "digests": { "lockset": true, - "thread": false, + "fresh": false, "region": false, "symb_locks": false, diff --git a/conf/race-digests/tid+mutex.json b/conf/race-digests/tid+mutex.json index 98e4732913..f5baca160c 100644 --- a/conf/race-digests/tid+mutex.json +++ b/conf/race-digests/tid+mutex.json @@ -56,7 +56,7 @@ "call": false, "digests": { "lockset": true, - "thread": false, + "fresh": false, "region": false, "symb_locks": false, diff --git a/conf/race-digests/tid+thread.json b/conf/race-digests/tid+thread.json deleted file mode 100644 index bd4dea95b7..0000000000 --- a/conf/race-digests/tid+thread.json +++ /dev/null @@ -1,128 +0,0 @@ -{ - "ana": { - "sv-comp": { - "enabled": true, - "functions": true - }, - "int": { - "def_exc": true, - "enums": false, - "interval": true - }, - "float": { - "interval": true, - "evaluate_math_functions": true - }, - "activated": [ - "base", - "threadid", - "threadflag", - "threadreturn", - "mallocWrapper", - "mutexEvents", - "mutex", - "access", - "race", - "escape", - "expRelation", - "mhp", - "assert", - "var_eq", - "symb_locks", - "region", - "thread", - "threadJoins", - "abortUnless" - ], - "path_sens": [ - "mutex", - "malloc_null", - "uninit", - "expsplit", - "activeSetjmp", - "memLeak", - "threadflag" - ], - "context": { - "widen": false - }, - "base": { - "arrays": { - "domain": "partitioned" - } - }, - "race": { - "free": false, - "call": false, - "digests": { - "lockset": false, - "thread": true, - "fresh": false, - "region": false, - "symb_locks": false, - "threadflag": false, - "tid": true, - "join" : false - } - }, - "autotune": { - "enabled": true, - "activated": [ - "singleThreaded", - "mallocWrappers", - "noRecursiveIntervals", - "enums", - "congruence", - "octagon", - "wideningThresholds", - "loopUnrollHeuristic", - "memsafetySpecification", - "noOverflows", - "termination", - "tmpSpecialAnalysis" - ] - } - }, - "exp": { - "region-offsets": true - }, - "solver": "td3", - "sem": { - "unknown_function": { - "spawn": false - }, - "int": { - "signed_overflow": "assume_none" - }, - "null-pointer": { - "dereference": "assume_none" - } - }, - "witness": { - "graphml": { - "enabled": true, - "id": "enumerate", - "unknown": false - }, - "yaml": { - "enabled": true, - "format-version": "2.0", - "entry-types": [ - "invariant_set" - ], - "invariant-types": [ - "loop_invariant" - ] - }, - "invariant": { - "loop-head": true, - "after-lock": false, - "other": false, - "accessed": false, - "exact": true - } - }, - "pre": { - "enabled": false - } -} diff --git a/conf/race-digests/tid-only.json b/conf/race-digests/tid-only.json index 90acc8fd5a..c97b857073 100644 --- a/conf/race-digests/tid-only.json +++ b/conf/race-digests/tid-only.json @@ -56,7 +56,7 @@ "call": false, "digests": { "lockset": false, - "thread": false, + "fresh": false, "region": false, "symb_locks": false, diff --git a/src/analyses/threadFlag.ml b/src/analyses/threadFlag.ml index 454ea28961..a48bbde9bc 100644 --- a/src/analyses/threadFlag.ml +++ b/src/analyses/threadFlag.ml @@ -54,15 +54,30 @@ struct module A = struct - include BoolDomain.Bool - let name () = "multi" - let may_race m1 m2 = + include Lattice.Prod(Flag)(BoolDomain.MayBool) + let name () = "threadflag" + + let may_race (m1,b1) (m2,b2) = let use_threadflag = GobConfig.get_bool "ana.race.digests.threadflag" in - (not use_threadflag) || (m1 && m2) (* kill access when single threaded *) - let should_print m = not m + let both_mt = Flag.is_multi m1 && Flag.is_multi m2 in + let one_not_main = Flag.is_not_main m1 || Flag.is_not_main m2 in + ((not use_threadflag) || (both_mt && one_not_main)) && b1 && b2 + + (* kill access when single threaded *) + + let should_print m = true end + let access man _ = - is_currently_multi (Analyses.ask_of_man man) + let st = + if GobConfig.get_bool "ana.race.digests.join" then + is_currently_multi (Analyses.ask_of_man man) + else if GobConfig.get_bool "ana.race.digests.tid" then + has_ever_been_multi (Analyses.ask_of_man man) + else + true + in + ((man.local,st):A.t) let threadenter man ~multiple lval f args = if not (has_ever_been_multi (Analyses.ask_of_man man)) then diff --git a/src/analyses/threadId.ml b/src/analyses/threadId.ml index d9724b2c2e..c6e521b1d5 100644 --- a/src/analyses/threadId.ml +++ b/src/analyses/threadId.ml @@ -133,7 +133,7 @@ struct include Printable.Option (ThreadLifted) (struct let name = "nonunique" end) let name () = "thread" let may_race (t1: t) (t2: t) = - let use_tid = GobConfig.get_bool "ana.race.digests.thread" in + let use_tid = GobConfig.get_bool "ana.race.digests.tid" in (not use_tid) || match t1, t2 with | Some t1, Some t2 when ThreadLifted.equal t1 t2 -> false (* only unique threads *) diff --git a/src/config/options.schema.json b/src/config/options.schema.json index 6bcab0d253..8a11ed88de 100644 --- a/src/config/options.schema.json +++ b/src/config/options.schema.json @@ -1116,12 +1116,6 @@ "type" : "boolean", "default" : true }, - "thread" : { - "title": "ana.race.digests.thread", - "description": "TODO! How does relate to the MHP one? Seems to hit only in one case", - "type" : "boolean", - "default" : true - }, "fresh" : { "title": "ana.race.digests.fresh", "description": "Use freshness analysis for excluding data races.", From 46aeaa1c3fb3c2ad6eafeacaf15756e0cfac7305 Mon Sep 17 00:00:00 2001 From: Michael Schwarz Date: Wed, 28 May 2025 17:25:28 +0200 Subject: [PATCH 48/68] Push --- src/analyses/threadFlag.ml | 2 +- tests/regression/04-mutex/01-simple_rc.t | 24 ++++++------- .../regression/04-mutex/49-type-invariants.t | 36 +++++++++---------- .../04-mutex/77-type-nested-fields.t | 18 +++++----- .../04-mutex/79-type-nested-fields-deep1.t | 18 +++++----- .../04-mutex/80-type-nested-fields-deep2.t | 18 +++++----- .../04-mutex/84-distribute-fields-1.t | 18 +++++----- .../04-mutex/85-distribute-fields-2.t | 18 +++++----- .../04-mutex/86-distribute-fields-3.t | 18 +++++----- .../04-mutex/87-distribute-fields-4.t | 12 +++---- .../04-mutex/88-distribute-fields-5.t | 12 +++---- .../04-mutex/89-distribute-fields-6.t | 12 +++---- .../04-mutex/90-distribute-fields-type-1.t | 24 ++++++------- .../04-mutex/91-distribute-fields-type-2.t | 24 ++++++------- .../04-mutex/92-distribute-fields-type-deep.t | 24 ++++++------- .../93-distribute-fields-type-global.t | 24 ++++++------- tests/regression/06-symbeq/14-list_entry_rc.t | 28 +++++++-------- tests/regression/06-symbeq/16-type_rc.t | 18 +++++----- tests/regression/06-symbeq/21-mult_accs_rc.t | 18 +++++----- .../63-access-threadspawn-lval.t | 7 ++-- .../13-privatized/64-access-invalidate.t | 3 +- tests/regression/29-svcomp/16-atomic_priv.t | 12 +++---- .../regression/36-apron/12-traces-min-rpb1.t | 16 ++++----- tests/regression/45-escape/51-fresh-global.t | 4 +-- .../46-apron2/95-witness-mm-escape.t | 5 +++ .../56-witness/68-ghost-ambiguous-idx.t | 6 ++-- .../56-witness/69-ghost-ptr-protection.t | 12 +++---- .../74-invalid_deref/01-oob-heap-simple.t | 5 +++ 28 files changed, 224 insertions(+), 212 deletions(-) diff --git a/src/analyses/threadFlag.ml b/src/analyses/threadFlag.ml index a48bbde9bc..1e362fa104 100644 --- a/src/analyses/threadFlag.ml +++ b/src/analyses/threadFlag.ml @@ -63,7 +63,7 @@ struct let one_not_main = Flag.is_not_main m1 || Flag.is_not_main m2 in ((not use_threadflag) || (both_mt && one_not_main)) && b1 && b2 - (* kill access when single threaded *) + (* kill access when single threaded *) let should_print m = true end diff --git a/tests/regression/04-mutex/01-simple_rc.t b/tests/regression/04-mutex/01-simple_rc.t index bd0bc0e161..f7b1131840 100644 --- a/tests/regression/04-mutex/01-simple_rc.t +++ b/tests/regression/04-mutex/01-simple_rc.t @@ -1,9 +1,9 @@ $ goblint --enable warn.deterministic 01-simple_rc.c 2>&1 | tee default-output.txt [Warning][Race] Memory location myglobal (race with conf. 110): (01-simple_rc.c:4:5-4:13) - write with [lock:{mutex1}, thread:[main, t_fun@01-simple_rc.c:17:3-17:40]] (conf. 110) (exp: & myglobal) (01-simple_rc.c:10:3-10:22) - write with [mhp:{created={[main, t_fun@01-simple_rc.c:17:3-17:40]}}, lock:{mutex2}, thread:[main]] (conf. 110) (exp: & myglobal) (01-simple_rc.c:19:3-19:22) - read with [lock:{mutex1}, thread:[main, t_fun@01-simple_rc.c:17:3-17:40]] (conf. 110) (exp: & myglobal) (01-simple_rc.c:10:3-10:22) - read with [mhp:{created={[main, t_fun@01-simple_rc.c:17:3-17:40]}}, lock:{mutex2}, thread:[main]] (conf. 110) (exp: & myglobal) (01-simple_rc.c:19:3-19:22) + write with [lock:{mutex1}, threadflag:(MT mode:Multithreaded (other), bool:true), thread:[main, t_fun@01-simple_rc.c:17:3-17:40]] (conf. 110) (exp: & myglobal) (01-simple_rc.c:10:3-10:22) + write with [mhp:{created={[main, t_fun@01-simple_rc.c:17:3-17:40]}}, lock:{mutex2}, threadflag:(MT mode:Multithreaded (main), bool:true), thread:[main]] (conf. 110) (exp: & myglobal) (01-simple_rc.c:19:3-19:22) + read with [lock:{mutex1}, threadflag:(MT mode:Multithreaded (other), bool:true), thread:[main, t_fun@01-simple_rc.c:17:3-17:40]] (conf. 110) (exp: & myglobal) (01-simple_rc.c:10:3-10:22) + read with [mhp:{created={[main, t_fun@01-simple_rc.c:17:3-17:40]}}, lock:{mutex2}, threadflag:(MT mode:Multithreaded (main), bool:true), thread:[main]] (conf. 110) (exp: & myglobal) (01-simple_rc.c:19:3-19:22) [Info][Race] Memory locations race summary: safe: 0 vulnerable: 0 @@ -18,13 +18,13 @@ $ diff default-output.txt full-output.txt 2,5c2,5 - < write with [lock:{mutex1}, thread:[main, t_fun@01-simple_rc.c:17:3-17:40]] (conf. 110) (exp: & myglobal) (01-simple_rc.c:10:3-10:22) - < write with [mhp:{created={[main, t_fun@01-simple_rc.c:17:3-17:40]}}, lock:{mutex2}, thread:[main]] (conf. 110) (exp: & myglobal) (01-simple_rc.c:19:3-19:22) - < read with [lock:{mutex1}, thread:[main, t_fun@01-simple_rc.c:17:3-17:40]] (conf. 110) (exp: & myglobal) (01-simple_rc.c:10:3-10:22) - < read with [mhp:{created={[main, t_fun@01-simple_rc.c:17:3-17:40]}}, lock:{mutex2}, thread:[main]] (conf. 110) (exp: & myglobal) (01-simple_rc.c:19:3-19:22) + < write with [lock:{mutex1}, threadflag:(MT mode:Multithreaded (other), bool:true), thread:[main, t_fun@01-simple_rc.c:17:3-17:40]] (conf. 110) (exp: & myglobal) (01-simple_rc.c:10:3-10:22) + < write with [mhp:{created={[main, t_fun@01-simple_rc.c:17:3-17:40]}}, lock:{mutex2}, threadflag:(MT mode:Multithreaded (main), bool:true), thread:[main]] (conf. 110) (exp: & myglobal) (01-simple_rc.c:19:3-19:22) + < read with [lock:{mutex1}, threadflag:(MT mode:Multithreaded (other), bool:true), thread:[main, t_fun@01-simple_rc.c:17:3-17:40]] (conf. 110) (exp: & myglobal) (01-simple_rc.c:10:3-10:22) + < read with [mhp:{created={[main, t_fun@01-simple_rc.c:17:3-17:40]}}, lock:{mutex2}, threadflag:(MT mode:Multithreaded (main), bool:true), thread:[main]] (conf. 110) (exp: & myglobal) (01-simple_rc.c:19:3-19:22) --- - > write with [mhp:{tid=[main, t_fun@01-simple_rc.c:17:3-17:40#⊤]}, lock:{mutex1}, thread:[main, t_fun@01-simple_rc.c:17:3-17:40#⊤]] (conf. 110) (exp: & myglobal) (01-simple_rc.c:10:3-10:22) - > write with [mhp:{tid=[main]; created={[main, t_fun@01-simple_rc.c:17:3-17:40#⊤]}}, lock:{mutex2}, thread:[main]] (conf. 110) (exp: & myglobal) (01-simple_rc.c:19:3-19:22) - > read with [mhp:{tid=[main, t_fun@01-simple_rc.c:17:3-17:40#⊤]}, lock:{mutex1}, thread:[main, t_fun@01-simple_rc.c:17:3-17:40#⊤]] (conf. 110) (exp: & myglobal) (01-simple_rc.c:10:3-10:22) - > read with [mhp:{tid=[main]; created={[main, t_fun@01-simple_rc.c:17:3-17:40#⊤]}}, lock:{mutex2}, thread:[main]] (conf. 110) (exp: & myglobal) (01-simple_rc.c:19:3-19:22) + > write with [mhp:{tid=[main, t_fun@01-simple_rc.c:17:3-17:40#⊤]}, lock:{mutex1}, threadflag:(MT mode:Multithreaded (other), bool:true), thread:[main, t_fun@01-simple_rc.c:17:3-17:40#⊤]] (conf. 110) (exp: & myglobal) (01-simple_rc.c:10:3-10:22) + > write with [mhp:{tid=[main]; created={[main, t_fun@01-simple_rc.c:17:3-17:40#⊤]}}, lock:{mutex2}, threadflag:(MT mode:Multithreaded (main), bool:true), thread:[main]] (conf. 110) (exp: & myglobal) (01-simple_rc.c:19:3-19:22) + > read with [mhp:{tid=[main, t_fun@01-simple_rc.c:17:3-17:40#⊤]}, lock:{mutex1}, threadflag:(MT mode:Multithreaded (other), bool:true), thread:[main, t_fun@01-simple_rc.c:17:3-17:40#⊤]] (conf. 110) (exp: & myglobal) (01-simple_rc.c:10:3-10:22) + > read with [mhp:{tid=[main]; created={[main, t_fun@01-simple_rc.c:17:3-17:40#⊤]}}, lock:{mutex2}, threadflag:(MT mode:Multithreaded (main), bool:true), thread:[main]] (conf. 110) (exp: & myglobal) (01-simple_rc.c:19:3-19:22) [1] diff --git a/tests/regression/04-mutex/49-type-invariants.t b/tests/regression/04-mutex/49-type-invariants.t index d757519b29..cd12bbd170 100644 --- a/tests/regression/04-mutex/49-type-invariants.t +++ b/tests/regression/04-mutex/49-type-invariants.t @@ -1,15 +1,15 @@ $ goblint --enable warn.deterministic --enable ana.race.direct-arithmetic --enable allglobs 49-type-invariants.c 2>&1 | tee default-output-1.txt [Warning][Behavior > Undefined > NullPointerDereference][CWE-476] May dereference NULL pointer (49-type-invariants.c:21:3-21:21) [Warning][Race] Memory location s.field (race with conf. 110): (49-type-invariants.c:8:10-8:11) - write with [mhp:{created={[main, t_fun@49-type-invariants.c:20:3-20:40]}}, thread:[main]] (conf. 100) (exp: & tmp->field) (49-type-invariants.c:21:3-21:21) - read with thread:[main, t_fun@49-type-invariants.c:20:3-20:40] (conf. 110) (exp: & s.field) (49-type-invariants.c:11:3-11:23) + write with [mhp:{created={[main, t_fun@49-type-invariants.c:20:3-20:40]}}, threadflag:(MT mode:Multithreaded (main), bool:true), thread:[main]] (conf. 100) (exp: & tmp->field) (49-type-invariants.c:21:3-21:21) + read with [threadflag:(MT mode:Multithreaded (other), bool:true), thread:[main, t_fun@49-type-invariants.c:20:3-20:40]] (conf. 110) (exp: & s.field) (49-type-invariants.c:11:3-11:23) [Info][Race] Memory locations race summary: safe: 1 vulnerable: 0 unsafe: 1 total memory locations: 2 [Success][Race] Memory location (struct S).field (safe): - write with [mhp:{created={[main, t_fun@49-type-invariants.c:20:3-20:40]}}, thread:[main]] (conf. 100) (exp: & tmp->field) (49-type-invariants.c:21:3-21:21) + write with [mhp:{created={[main, t_fun@49-type-invariants.c:20:3-20:40]}}, threadflag:(MT mode:Multithreaded (main), bool:true), thread:[main]] (conf. 100) (exp: & tmp->field) (49-type-invariants.c:21:3-21:21) [Info][Deadcode] Logical lines of code (LLoC) summary: live: 7 dead: 0 @@ -24,15 +24,15 @@ $ goblint --enable warn.deterministic --disable ana.race.direct-arithmetic --enable allglobs 49-type-invariants.c 2>&1 | tee default-output-2.txt [Warning][Behavior > Undefined > NullPointerDereference][CWE-476] May dereference NULL pointer (49-type-invariants.c:21:3-21:21) [Warning][Race] Memory location s.field (race with conf. 110): (49-type-invariants.c:8:10-8:11) - write with [mhp:{created={[main, t_fun@49-type-invariants.c:20:3-20:40]}}, thread:[main]] (conf. 100) (exp: & tmp->field) (49-type-invariants.c:21:3-21:21) - read with thread:[main, t_fun@49-type-invariants.c:20:3-20:40] (conf. 110) (exp: & s.field) (49-type-invariants.c:11:3-11:23) + write with [mhp:{created={[main, t_fun@49-type-invariants.c:20:3-20:40]}}, threadflag:(MT mode:Multithreaded (main), bool:true), thread:[main]] (conf. 100) (exp: & tmp->field) (49-type-invariants.c:21:3-21:21) + read with [threadflag:(MT mode:Multithreaded (other), bool:true), thread:[main, t_fun@49-type-invariants.c:20:3-20:40]] (conf. 110) (exp: & s.field) (49-type-invariants.c:11:3-11:23) [Info][Race] Memory locations race summary: safe: 1 vulnerable: 0 unsafe: 1 total memory locations: 2 [Success][Race] Memory location (struct S).field (safe): - write with [mhp:{created={[main, t_fun@49-type-invariants.c:20:3-20:40]}}, thread:[main]] (conf. 100) (exp: & tmp->field) (49-type-invariants.c:21:3-21:21) + write with [mhp:{created={[main, t_fun@49-type-invariants.c:20:3-20:40]}}, threadflag:(MT mode:Multithreaded (main), bool:true), thread:[main]] (conf. 100) (exp: & tmp->field) (49-type-invariants.c:21:3-21:21) [Info][Deadcode] Logical lines of code (LLoC) summary: live: 7 dead: 0 @@ -48,28 +48,28 @@ $ diff default-output-1.txt full-output-1.txt 3,4c3,4 - < write with [mhp:{created={[main, t_fun@49-type-invariants.c:20:3-20:40]}}, thread:[main]] (conf. 100) (exp: & tmp->field) (49-type-invariants.c:21:3-21:21) - < read with thread:[main, t_fun@49-type-invariants.c:20:3-20:40] (conf. 110) (exp: & s.field) (49-type-invariants.c:11:3-11:23) + < write with [mhp:{created={[main, t_fun@49-type-invariants.c:20:3-20:40]}}, threadflag:(MT mode:Multithreaded (main), bool:true), thread:[main]] (conf. 100) (exp: & tmp->field) (49-type-invariants.c:21:3-21:21) + < read with [threadflag:(MT mode:Multithreaded (other), bool:true), thread:[main, t_fun@49-type-invariants.c:20:3-20:40]] (conf. 110) (exp: & s.field) (49-type-invariants.c:11:3-11:23) --- - > write with [mhp:{tid=[main]; created={[main, t_fun@49-type-invariants.c:20:3-20:40#⊤]}}, thread:[main]] (conf. 100) (exp: & tmp->field) (49-type-invariants.c:21:3-21:21) - > read with [mhp:{tid=[main, t_fun@49-type-invariants.c:20:3-20:40#⊤]}, thread:[main, t_fun@49-type-invariants.c:20:3-20:40#⊤]] (conf. 110) (exp: & s.field) (49-type-invariants.c:11:3-11:23) + > write with [mhp:{tid=[main]; created={[main, t_fun@49-type-invariants.c:20:3-20:40#⊤]}}, threadflag:(MT mode:Multithreaded (main), bool:true), thread:[main]] (conf. 100) (exp: & tmp->field) (49-type-invariants.c:21:3-21:21) + > read with [mhp:{tid=[main, t_fun@49-type-invariants.c:20:3-20:40#⊤]}, threadflag:(MT mode:Multithreaded (other), bool:true), thread:[main, t_fun@49-type-invariants.c:20:3-20:40#⊤]] (conf. 110) (exp: & s.field) (49-type-invariants.c:11:3-11:23) 11c11 - < write with [mhp:{created={[main, t_fun@49-type-invariants.c:20:3-20:40]}}, thread:[main]] (conf. 100) (exp: & tmp->field) (49-type-invariants.c:21:3-21:21) + < write with [mhp:{created={[main, t_fun@49-type-invariants.c:20:3-20:40]}}, threadflag:(MT mode:Multithreaded (main), bool:true), thread:[main]] (conf. 100) (exp: & tmp->field) (49-type-invariants.c:21:3-21:21) --- - > write with [mhp:{tid=[main]; created={[main, t_fun@49-type-invariants.c:20:3-20:40#⊤]}}, thread:[main]] (conf. 100) (exp: & tmp->field) (49-type-invariants.c:21:3-21:21) + > write with [mhp:{tid=[main]; created={[main, t_fun@49-type-invariants.c:20:3-20:40#⊤]}}, threadflag:(MT mode:Multithreaded (main), bool:true), thread:[main]] (conf. 100) (exp: & tmp->field) (49-type-invariants.c:21:3-21:21) [1] $ goblint --enable warn.deterministic --disable ana.race.direct-arithmetic --enable allglobs --enable dbg.full-output 49-type-invariants.c > full-output-2.txt 2>&1 $ diff default-output-2.txt full-output-2.txt 3,4c3,4 - < write with [mhp:{created={[main, t_fun@49-type-invariants.c:20:3-20:40]}}, thread:[main]] (conf. 100) (exp: & tmp->field) (49-type-invariants.c:21:3-21:21) - < read with thread:[main, t_fun@49-type-invariants.c:20:3-20:40] (conf. 110) (exp: & s.field) (49-type-invariants.c:11:3-11:23) + < write with [mhp:{created={[main, t_fun@49-type-invariants.c:20:3-20:40]}}, threadflag:(MT mode:Multithreaded (main), bool:true), thread:[main]] (conf. 100) (exp: & tmp->field) (49-type-invariants.c:21:3-21:21) + < read with [threadflag:(MT mode:Multithreaded (other), bool:true), thread:[main, t_fun@49-type-invariants.c:20:3-20:40]] (conf. 110) (exp: & s.field) (49-type-invariants.c:11:3-11:23) --- - > write with [mhp:{tid=[main]; created={[main, t_fun@49-type-invariants.c:20:3-20:40#⊤]}}, thread:[main]] (conf. 100) (exp: & tmp->field) (49-type-invariants.c:21:3-21:21) - > read with [mhp:{tid=[main, t_fun@49-type-invariants.c:20:3-20:40#⊤]}, thread:[main, t_fun@49-type-invariants.c:20:3-20:40#⊤]] (conf. 110) (exp: & s.field) (49-type-invariants.c:11:3-11:23) + > write with [mhp:{tid=[main]; created={[main, t_fun@49-type-invariants.c:20:3-20:40#⊤]}}, threadflag:(MT mode:Multithreaded (main), bool:true), thread:[main]] (conf. 100) (exp: & tmp->field) (49-type-invariants.c:21:3-21:21) + > read with [mhp:{tid=[main, t_fun@49-type-invariants.c:20:3-20:40#⊤]}, threadflag:(MT mode:Multithreaded (other), bool:true), thread:[main, t_fun@49-type-invariants.c:20:3-20:40#⊤]] (conf. 110) (exp: & s.field) (49-type-invariants.c:11:3-11:23) 11c11 - < write with [mhp:{created={[main, t_fun@49-type-invariants.c:20:3-20:40]}}, thread:[main]] (conf. 100) (exp: & tmp->field) (49-type-invariants.c:21:3-21:21) + < write with [mhp:{created={[main, t_fun@49-type-invariants.c:20:3-20:40]}}, threadflag:(MT mode:Multithreaded (main), bool:true), thread:[main]] (conf. 100) (exp: & tmp->field) (49-type-invariants.c:21:3-21:21) --- - > write with [mhp:{tid=[main]; created={[main, t_fun@49-type-invariants.c:20:3-20:40#⊤]}}, thread:[main]] (conf. 100) (exp: & tmp->field) (49-type-invariants.c:21:3-21:21) + > write with [mhp:{tid=[main]; created={[main, t_fun@49-type-invariants.c:20:3-20:40#⊤]}}, threadflag:(MT mode:Multithreaded (main), bool:true), thread:[main]] (conf. 100) (exp: & tmp->field) (49-type-invariants.c:21:3-21:21) [1] diff --git a/tests/regression/04-mutex/77-type-nested-fields.t b/tests/regression/04-mutex/77-type-nested-fields.t index 15559cefec..7041b8e19c 100644 --- a/tests/regression/04-mutex/77-type-nested-fields.t +++ b/tests/regression/04-mutex/77-type-nested-fields.t @@ -2,15 +2,15 @@ [Warning][Behavior > Undefined > NullPointerDereference][CWE-476] May dereference NULL pointer (77-type-nested-fields.c:31:3-31:20) [Warning][Behavior > Undefined > NullPointerDereference][CWE-476] May dereference NULL pointer (77-type-nested-fields.c:38:3-38:22) [Warning][Race] Memory location (struct T).s.field (race with conf. 100): - write with thread:[main, t_fun@77-type-nested-fields.c:37:3-37:40] (conf. 100) (exp: & tmp->field) (77-type-nested-fields.c:31:3-31:20) - write with [mhp:{created={[main, t_fun@77-type-nested-fields.c:37:3-37:40]}}, thread:[main]] (conf. 100) (exp: & tmp->s.field) (77-type-nested-fields.c:38:3-38:22) + write with [threadflag:(MT mode:Multithreaded (other), bool:true), thread:[main, t_fun@77-type-nested-fields.c:37:3-37:40]] (conf. 100) (exp: & tmp->field) (77-type-nested-fields.c:31:3-31:20) + write with [mhp:{created={[main, t_fun@77-type-nested-fields.c:37:3-37:40]}}, threadflag:(MT mode:Multithreaded (main), bool:true), thread:[main]] (conf. 100) (exp: & tmp->s.field) (77-type-nested-fields.c:38:3-38:22) [Info][Race] Memory locations race summary: safe: 1 vulnerable: 0 unsafe: 1 total memory locations: 2 [Success][Race] Memory location (struct S).field (safe): - write with thread:[main, t_fun@77-type-nested-fields.c:37:3-37:40] (conf. 100) (exp: & tmp->field) (77-type-nested-fields.c:31:3-31:20) + write with [threadflag:(MT mode:Multithreaded (other), bool:true), thread:[main, t_fun@77-type-nested-fields.c:37:3-37:40]] (conf. 100) (exp: & tmp->field) (77-type-nested-fields.c:31:3-31:20) [Info][Deadcode] Logical lines of code (LLoC) summary: live: 7 dead: 0 @@ -29,13 +29,13 @@ $ diff default-output.txt full-output.txt 4,5c4,5 - < write with thread:[main, t_fun@77-type-nested-fields.c:37:3-37:40] (conf. 100) (exp: & tmp->field) (77-type-nested-fields.c:31:3-31:20) - < write with [mhp:{created={[main, t_fun@77-type-nested-fields.c:37:3-37:40]}}, thread:[main]] (conf. 100) (exp: & tmp->s.field) (77-type-nested-fields.c:38:3-38:22) + < write with [threadflag:(MT mode:Multithreaded (other), bool:true), thread:[main, t_fun@77-type-nested-fields.c:37:3-37:40]] (conf. 100) (exp: & tmp->field) (77-type-nested-fields.c:31:3-31:20) + < write with [mhp:{created={[main, t_fun@77-type-nested-fields.c:37:3-37:40]}}, threadflag:(MT mode:Multithreaded (main), bool:true), thread:[main]] (conf. 100) (exp: & tmp->s.field) (77-type-nested-fields.c:38:3-38:22) --- - > write with [mhp:{tid=[main, t_fun@77-type-nested-fields.c:37:3-37:40#⊤]}, thread:[main, t_fun@77-type-nested-fields.c:37:3-37:40#⊤]] (conf. 100) (exp: & tmp->field) (77-type-nested-fields.c:31:3-31:20) - > write with [mhp:{tid=[main]; created={[main, t_fun@77-type-nested-fields.c:37:3-37:40#⊤]}}, thread:[main]] (conf. 100) (exp: & tmp->s.field) (77-type-nested-fields.c:38:3-38:22) + > write with [mhp:{tid=[main, t_fun@77-type-nested-fields.c:37:3-37:40#⊤]}, threadflag:(MT mode:Multithreaded (other), bool:true), thread:[main, t_fun@77-type-nested-fields.c:37:3-37:40#⊤]] (conf. 100) (exp: & tmp->field) (77-type-nested-fields.c:31:3-31:20) + > write with [mhp:{tid=[main]; created={[main, t_fun@77-type-nested-fields.c:37:3-37:40#⊤]}}, threadflag:(MT mode:Multithreaded (main), bool:true), thread:[main]] (conf. 100) (exp: & tmp->s.field) (77-type-nested-fields.c:38:3-38:22) 12c12 - < write with thread:[main, t_fun@77-type-nested-fields.c:37:3-37:40] (conf. 100) (exp: & tmp->field) (77-type-nested-fields.c:31:3-31:20) + < write with [threadflag:(MT mode:Multithreaded (other), bool:true), thread:[main, t_fun@77-type-nested-fields.c:37:3-37:40]] (conf. 100) (exp: & tmp->field) (77-type-nested-fields.c:31:3-31:20) --- - > write with [mhp:{tid=[main, t_fun@77-type-nested-fields.c:37:3-37:40#⊤]}, thread:[main, t_fun@77-type-nested-fields.c:37:3-37:40#⊤]] (conf. 100) (exp: & tmp->field) (77-type-nested-fields.c:31:3-31:20) + > write with [mhp:{tid=[main, t_fun@77-type-nested-fields.c:37:3-37:40#⊤]}, threadflag:(MT mode:Multithreaded (other), bool:true), thread:[main, t_fun@77-type-nested-fields.c:37:3-37:40#⊤]] (conf. 100) (exp: & tmp->field) (77-type-nested-fields.c:31:3-31:20) [1] diff --git a/tests/regression/04-mutex/79-type-nested-fields-deep1.t b/tests/regression/04-mutex/79-type-nested-fields-deep1.t index 680200aecd..857fa3aaf1 100644 --- a/tests/regression/04-mutex/79-type-nested-fields-deep1.t +++ b/tests/regression/04-mutex/79-type-nested-fields-deep1.t @@ -2,15 +2,15 @@ [Warning][Behavior > Undefined > NullPointerDereference][CWE-476] May dereference NULL pointer (79-type-nested-fields-deep1.c:36:3-36:20) [Warning][Behavior > Undefined > NullPointerDereference][CWE-476] May dereference NULL pointer (79-type-nested-fields-deep1.c:43:3-43:24) [Warning][Race] Memory location (struct U).t.s.field (race with conf. 100): - write with thread:[main, t_fun@79-type-nested-fields-deep1.c:42:3-42:40] (conf. 100) (exp: & tmp->field) (79-type-nested-fields-deep1.c:36:3-36:20) - write with [mhp:{created={[main, t_fun@79-type-nested-fields-deep1.c:42:3-42:40]}}, thread:[main]] (conf. 100) (exp: & tmp->t.s.field) (79-type-nested-fields-deep1.c:43:3-43:24) + write with [threadflag:(MT mode:Multithreaded (other), bool:true), thread:[main, t_fun@79-type-nested-fields-deep1.c:42:3-42:40]] (conf. 100) (exp: & tmp->field) (79-type-nested-fields-deep1.c:36:3-36:20) + write with [mhp:{created={[main, t_fun@79-type-nested-fields-deep1.c:42:3-42:40]}}, threadflag:(MT mode:Multithreaded (main), bool:true), thread:[main]] (conf. 100) (exp: & tmp->t.s.field) (79-type-nested-fields-deep1.c:43:3-43:24) [Info][Race] Memory locations race summary: safe: 1 vulnerable: 0 unsafe: 1 total memory locations: 2 [Success][Race] Memory location (struct S).field (safe): - write with thread:[main, t_fun@79-type-nested-fields-deep1.c:42:3-42:40] (conf. 100) (exp: & tmp->field) (79-type-nested-fields-deep1.c:36:3-36:20) + write with [threadflag:(MT mode:Multithreaded (other), bool:true), thread:[main, t_fun@79-type-nested-fields-deep1.c:42:3-42:40]] (conf. 100) (exp: & tmp->field) (79-type-nested-fields-deep1.c:36:3-36:20) [Info][Deadcode] Logical lines of code (LLoC) summary: live: 7 dead: 0 @@ -29,13 +29,13 @@ $ diff default-output.txt full-output.txt 4,5c4,5 - < write with thread:[main, t_fun@79-type-nested-fields-deep1.c:42:3-42:40] (conf. 100) (exp: & tmp->field) (79-type-nested-fields-deep1.c:36:3-36:20) - < write with [mhp:{created={[main, t_fun@79-type-nested-fields-deep1.c:42:3-42:40]}}, thread:[main]] (conf. 100) (exp: & tmp->t.s.field) (79-type-nested-fields-deep1.c:43:3-43:24) + < write with [threadflag:(MT mode:Multithreaded (other), bool:true), thread:[main, t_fun@79-type-nested-fields-deep1.c:42:3-42:40]] (conf. 100) (exp: & tmp->field) (79-type-nested-fields-deep1.c:36:3-36:20) + < write with [mhp:{created={[main, t_fun@79-type-nested-fields-deep1.c:42:3-42:40]}}, threadflag:(MT mode:Multithreaded (main), bool:true), thread:[main]] (conf. 100) (exp: & tmp->t.s.field) (79-type-nested-fields-deep1.c:43:3-43:24) --- - > write with [mhp:{tid=[main, t_fun@79-type-nested-fields-deep1.c:42:3-42:40#⊤]}, thread:[main, t_fun@79-type-nested-fields-deep1.c:42:3-42:40#⊤]] (conf. 100) (exp: & tmp->field) (79-type-nested-fields-deep1.c:36:3-36:20) - > write with [mhp:{tid=[main]; created={[main, t_fun@79-type-nested-fields-deep1.c:42:3-42:40#⊤]}}, thread:[main]] (conf. 100) (exp: & tmp->t.s.field) (79-type-nested-fields-deep1.c:43:3-43:24) + > write with [mhp:{tid=[main, t_fun@79-type-nested-fields-deep1.c:42:3-42:40#⊤]}, threadflag:(MT mode:Multithreaded (other), bool:true), thread:[main, t_fun@79-type-nested-fields-deep1.c:42:3-42:40#⊤]] (conf. 100) (exp: & tmp->field) (79-type-nested-fields-deep1.c:36:3-36:20) + > write with [mhp:{tid=[main]; created={[main, t_fun@79-type-nested-fields-deep1.c:42:3-42:40#⊤]}}, threadflag:(MT mode:Multithreaded (main), bool:true), thread:[main]] (conf. 100) (exp: & tmp->t.s.field) (79-type-nested-fields-deep1.c:43:3-43:24) 12c12 - < write with thread:[main, t_fun@79-type-nested-fields-deep1.c:42:3-42:40] (conf. 100) (exp: & tmp->field) (79-type-nested-fields-deep1.c:36:3-36:20) + < write with [threadflag:(MT mode:Multithreaded (other), bool:true), thread:[main, t_fun@79-type-nested-fields-deep1.c:42:3-42:40]] (conf. 100) (exp: & tmp->field) (79-type-nested-fields-deep1.c:36:3-36:20) --- - > write with [mhp:{tid=[main, t_fun@79-type-nested-fields-deep1.c:42:3-42:40#⊤]}, thread:[main, t_fun@79-type-nested-fields-deep1.c:42:3-42:40#⊤]] (conf. 100) (exp: & tmp->field) (79-type-nested-fields-deep1.c:36:3-36:20) + > write with [mhp:{tid=[main, t_fun@79-type-nested-fields-deep1.c:42:3-42:40#⊤]}, threadflag:(MT mode:Multithreaded (other), bool:true), thread:[main, t_fun@79-type-nested-fields-deep1.c:42:3-42:40#⊤]] (conf. 100) (exp: & tmp->field) (79-type-nested-fields-deep1.c:36:3-36:20) [1] diff --git a/tests/regression/04-mutex/80-type-nested-fields-deep2.t b/tests/regression/04-mutex/80-type-nested-fields-deep2.t index 4a2811ccbd..dd4d6e90a8 100644 --- a/tests/regression/04-mutex/80-type-nested-fields-deep2.t +++ b/tests/regression/04-mutex/80-type-nested-fields-deep2.t @@ -2,15 +2,15 @@ [Warning][Behavior > Undefined > NullPointerDereference][CWE-476] May dereference NULL pointer (80-type-nested-fields-deep2.c:36:3-36:22) [Warning][Behavior > Undefined > NullPointerDereference][CWE-476] May dereference NULL pointer (80-type-nested-fields-deep2.c:43:3-43:24) [Warning][Race] Memory location (struct U).t.s.field (race with conf. 100): - write with thread:[main, t_fun@80-type-nested-fields-deep2.c:42:3-42:40] (conf. 100) (exp: & tmp->s.field) (80-type-nested-fields-deep2.c:36:3-36:22) - write with [mhp:{created={[main, t_fun@80-type-nested-fields-deep2.c:42:3-42:40]}}, thread:[main]] (conf. 100) (exp: & tmp->t.s.field) (80-type-nested-fields-deep2.c:43:3-43:24) + write with [threadflag:(MT mode:Multithreaded (other), bool:true), thread:[main, t_fun@80-type-nested-fields-deep2.c:42:3-42:40]] (conf. 100) (exp: & tmp->s.field) (80-type-nested-fields-deep2.c:36:3-36:22) + write with [mhp:{created={[main, t_fun@80-type-nested-fields-deep2.c:42:3-42:40]}}, threadflag:(MT mode:Multithreaded (main), bool:true), thread:[main]] (conf. 100) (exp: & tmp->t.s.field) (80-type-nested-fields-deep2.c:43:3-43:24) [Info][Race] Memory locations race summary: safe: 1 vulnerable: 0 unsafe: 1 total memory locations: 2 [Success][Race] Memory location (struct T).s.field (safe): - write with thread:[main, t_fun@80-type-nested-fields-deep2.c:42:3-42:40] (conf. 100) (exp: & tmp->s.field) (80-type-nested-fields-deep2.c:36:3-36:22) + write with [threadflag:(MT mode:Multithreaded (other), bool:true), thread:[main, t_fun@80-type-nested-fields-deep2.c:42:3-42:40]] (conf. 100) (exp: & tmp->s.field) (80-type-nested-fields-deep2.c:36:3-36:22) [Info][Deadcode] Logical lines of code (LLoC) summary: live: 7 dead: 0 @@ -29,13 +29,13 @@ $ diff default-output.txt full-output.txt 4,5c4,5 - < write with thread:[main, t_fun@80-type-nested-fields-deep2.c:42:3-42:40] (conf. 100) (exp: & tmp->s.field) (80-type-nested-fields-deep2.c:36:3-36:22) - < write with [mhp:{created={[main, t_fun@80-type-nested-fields-deep2.c:42:3-42:40]}}, thread:[main]] (conf. 100) (exp: & tmp->t.s.field) (80-type-nested-fields-deep2.c:43:3-43:24) + < write with [threadflag:(MT mode:Multithreaded (other), bool:true), thread:[main, t_fun@80-type-nested-fields-deep2.c:42:3-42:40]] (conf. 100) (exp: & tmp->s.field) (80-type-nested-fields-deep2.c:36:3-36:22) + < write with [mhp:{created={[main, t_fun@80-type-nested-fields-deep2.c:42:3-42:40]}}, threadflag:(MT mode:Multithreaded (main), bool:true), thread:[main]] (conf. 100) (exp: & tmp->t.s.field) (80-type-nested-fields-deep2.c:43:3-43:24) --- - > write with [mhp:{tid=[main, t_fun@80-type-nested-fields-deep2.c:42:3-42:40#⊤]}, thread:[main, t_fun@80-type-nested-fields-deep2.c:42:3-42:40#⊤]] (conf. 100) (exp: & tmp->s.field) (80-type-nested-fields-deep2.c:36:3-36:22) - > write with [mhp:{tid=[main]; created={[main, t_fun@80-type-nested-fields-deep2.c:42:3-42:40#⊤]}}, thread:[main]] (conf. 100) (exp: & tmp->t.s.field) (80-type-nested-fields-deep2.c:43:3-43:24) + > write with [mhp:{tid=[main, t_fun@80-type-nested-fields-deep2.c:42:3-42:40#⊤]}, threadflag:(MT mode:Multithreaded (other), bool:true), thread:[main, t_fun@80-type-nested-fields-deep2.c:42:3-42:40#⊤]] (conf. 100) (exp: & tmp->s.field) (80-type-nested-fields-deep2.c:36:3-36:22) + > write with [mhp:{tid=[main]; created={[main, t_fun@80-type-nested-fields-deep2.c:42:3-42:40#⊤]}}, threadflag:(MT mode:Multithreaded (main), bool:true), thread:[main]] (conf. 100) (exp: & tmp->t.s.field) (80-type-nested-fields-deep2.c:43:3-43:24) 12c12 - < write with thread:[main, t_fun@80-type-nested-fields-deep2.c:42:3-42:40] (conf. 100) (exp: & tmp->s.field) (80-type-nested-fields-deep2.c:36:3-36:22) + < write with [threadflag:(MT mode:Multithreaded (other), bool:true), thread:[main, t_fun@80-type-nested-fields-deep2.c:42:3-42:40]] (conf. 100) (exp: & tmp->s.field) (80-type-nested-fields-deep2.c:36:3-36:22) --- - > write with [mhp:{tid=[main, t_fun@80-type-nested-fields-deep2.c:42:3-42:40#⊤]}, thread:[main, t_fun@80-type-nested-fields-deep2.c:42:3-42:40#⊤]] (conf. 100) (exp: & tmp->s.field) (80-type-nested-fields-deep2.c:36:3-36:22) + > write with [mhp:{tid=[main, t_fun@80-type-nested-fields-deep2.c:42:3-42:40#⊤]}, threadflag:(MT mode:Multithreaded (other), bool:true), thread:[main, t_fun@80-type-nested-fields-deep2.c:42:3-42:40#⊤]] (conf. 100) (exp: & tmp->s.field) (80-type-nested-fields-deep2.c:36:3-36:22) [1] diff --git a/tests/regression/04-mutex/84-distribute-fields-1.t b/tests/regression/04-mutex/84-distribute-fields-1.t index 0fd55dcb53..cf30127d7d 100644 --- a/tests/regression/04-mutex/84-distribute-fields-1.t +++ b/tests/regression/04-mutex/84-distribute-fields-1.t @@ -1,14 +1,14 @@ $ goblint --enable warn.deterministic --enable allglobs 84-distribute-fields-1.c 2>&1 | tee default-output.txt [Warning][Race] Memory location s.data (race with conf. 110): (84-distribute-fields-1.c:9:10-9:11) - write with thread:[main, t_fun@84-distribute-fields-1.c:18:3-18:40] (conf. 110) (exp: & s.data) (84-distribute-fields-1.c:12:3-12:13) - write with [mhp:{created={[main, t_fun@84-distribute-fields-1.c:18:3-18:40]}}, thread:[main]] (conf. 110) (exp: & s) (84-distribute-fields-1.c:20:3-20:9) + write with [threadflag:(MT mode:Multithreaded (other), bool:true), thread:[main, t_fun@84-distribute-fields-1.c:18:3-18:40]] (conf. 110) (exp: & s.data) (84-distribute-fields-1.c:12:3-12:13) + write with [mhp:{created={[main, t_fun@84-distribute-fields-1.c:18:3-18:40]}}, threadflag:(MT mode:Multithreaded (main), bool:true), thread:[main]] (conf. 110) (exp: & s) (84-distribute-fields-1.c:20:3-20:9) [Info][Race] Memory locations race summary: safe: 1 vulnerable: 0 unsafe: 1 total memory locations: 2 [Success][Race] Memory location s (safe): (84-distribute-fields-1.c:9:10-9:11) - write with [mhp:{created={[main, t_fun@84-distribute-fields-1.c:18:3-18:40]}}, thread:[main]] (conf. 110) (exp: & s) (84-distribute-fields-1.c:20:3-20:9) + write with [mhp:{created={[main, t_fun@84-distribute-fields-1.c:18:3-18:40]}}, threadflag:(MT mode:Multithreaded (main), bool:true), thread:[main]] (conf. 110) (exp: & s) (84-distribute-fields-1.c:20:3-20:9) [Info][Deadcode] Logical lines of code (LLoC) summary: live: 8 dead: 0 @@ -18,13 +18,13 @@ $ diff default-output.txt full-output.txt 2,3c2,3 - < write with thread:[main, t_fun@84-distribute-fields-1.c:18:3-18:40] (conf. 110) (exp: & s.data) (84-distribute-fields-1.c:12:3-12:13) - < write with [mhp:{created={[main, t_fun@84-distribute-fields-1.c:18:3-18:40]}}, thread:[main]] (conf. 110) (exp: & s) (84-distribute-fields-1.c:20:3-20:9) + < write with [threadflag:(MT mode:Multithreaded (other), bool:true), thread:[main, t_fun@84-distribute-fields-1.c:18:3-18:40]] (conf. 110) (exp: & s.data) (84-distribute-fields-1.c:12:3-12:13) + < write with [mhp:{created={[main, t_fun@84-distribute-fields-1.c:18:3-18:40]}}, threadflag:(MT mode:Multithreaded (main), bool:true), thread:[main]] (conf. 110) (exp: & s) (84-distribute-fields-1.c:20:3-20:9) --- - > write with [mhp:{tid=[main, t_fun@84-distribute-fields-1.c:18:3-18:40#⊤]}, thread:[main, t_fun@84-distribute-fields-1.c:18:3-18:40#⊤]] (conf. 110) (exp: & s.data) (84-distribute-fields-1.c:12:3-12:13) - > write with [mhp:{tid=[main]; created={[main, t_fun@84-distribute-fields-1.c:18:3-18:40#⊤]}}, thread:[main]] (conf. 110) (exp: & s) (84-distribute-fields-1.c:20:3-20:9) + > write with [mhp:{tid=[main, t_fun@84-distribute-fields-1.c:18:3-18:40#⊤]}, threadflag:(MT mode:Multithreaded (other), bool:true), thread:[main, t_fun@84-distribute-fields-1.c:18:3-18:40#⊤]] (conf. 110) (exp: & s.data) (84-distribute-fields-1.c:12:3-12:13) + > write with [mhp:{tid=[main]; created={[main, t_fun@84-distribute-fields-1.c:18:3-18:40#⊤]}}, threadflag:(MT mode:Multithreaded (main), bool:true), thread:[main]] (conf. 110) (exp: & s) (84-distribute-fields-1.c:20:3-20:9) 10c10 - < write with [mhp:{created={[main, t_fun@84-distribute-fields-1.c:18:3-18:40]}}, thread:[main]] (conf. 110) (exp: & s) (84-distribute-fields-1.c:20:3-20:9) + < write with [mhp:{created={[main, t_fun@84-distribute-fields-1.c:18:3-18:40]}}, threadflag:(MT mode:Multithreaded (main), bool:true), thread:[main]] (conf. 110) (exp: & s) (84-distribute-fields-1.c:20:3-20:9) --- - > write with [mhp:{tid=[main]; created={[main, t_fun@84-distribute-fields-1.c:18:3-18:40#⊤]}}, thread:[main]] (conf. 110) (exp: & s) (84-distribute-fields-1.c:20:3-20:9) + > write with [mhp:{tid=[main]; created={[main, t_fun@84-distribute-fields-1.c:18:3-18:40#⊤]}}, threadflag:(MT mode:Multithreaded (main), bool:true), thread:[main]] (conf. 110) (exp: & s) (84-distribute-fields-1.c:20:3-20:9) [1] diff --git a/tests/regression/04-mutex/85-distribute-fields-2.t b/tests/regression/04-mutex/85-distribute-fields-2.t index 7f8fb7c942..76ba6c759c 100644 --- a/tests/regression/04-mutex/85-distribute-fields-2.t +++ b/tests/regression/04-mutex/85-distribute-fields-2.t @@ -1,14 +1,14 @@ $ goblint --enable warn.deterministic --enable allglobs 85-distribute-fields-2.c 2>&1 | tee default-output.txt [Warning][Race] Memory location t.s.data (race with conf. 110): (85-distribute-fields-2.c:15:10-15:11) - write with thread:[main, t_fun@85-distribute-fields-2.c:24:3-24:40] (conf. 110) (exp: & t.s.data) (85-distribute-fields-2.c:18:3-18:15) - write with [mhp:{created={[main, t_fun@85-distribute-fields-2.c:24:3-24:40]}}, thread:[main]] (conf. 110) (exp: & t.s) (85-distribute-fields-2.c:26:3-26:11) + write with [threadflag:(MT mode:Multithreaded (other), bool:true), thread:[main, t_fun@85-distribute-fields-2.c:24:3-24:40]] (conf. 110) (exp: & t.s.data) (85-distribute-fields-2.c:18:3-18:15) + write with [mhp:{created={[main, t_fun@85-distribute-fields-2.c:24:3-24:40]}}, threadflag:(MT mode:Multithreaded (main), bool:true), thread:[main]] (conf. 110) (exp: & t.s) (85-distribute-fields-2.c:26:3-26:11) [Info][Race] Memory locations race summary: safe: 1 vulnerable: 0 unsafe: 1 total memory locations: 2 [Success][Race] Memory location t.s (safe): (85-distribute-fields-2.c:15:10-15:11) - write with [mhp:{created={[main, t_fun@85-distribute-fields-2.c:24:3-24:40]}}, thread:[main]] (conf. 110) (exp: & t.s) (85-distribute-fields-2.c:26:3-26:11) + write with [mhp:{created={[main, t_fun@85-distribute-fields-2.c:24:3-24:40]}}, threadflag:(MT mode:Multithreaded (main), bool:true), thread:[main]] (conf. 110) (exp: & t.s) (85-distribute-fields-2.c:26:3-26:11) [Info][Deadcode] Logical lines of code (LLoC) summary: live: 8 dead: 0 @@ -18,13 +18,13 @@ $ diff default-output.txt full-output.txt 2,3c2,3 - < write with thread:[main, t_fun@85-distribute-fields-2.c:24:3-24:40] (conf. 110) (exp: & t.s.data) (85-distribute-fields-2.c:18:3-18:15) - < write with [mhp:{created={[main, t_fun@85-distribute-fields-2.c:24:3-24:40]}}, thread:[main]] (conf. 110) (exp: & t.s) (85-distribute-fields-2.c:26:3-26:11) + < write with [threadflag:(MT mode:Multithreaded (other), bool:true), thread:[main, t_fun@85-distribute-fields-2.c:24:3-24:40]] (conf. 110) (exp: & t.s.data) (85-distribute-fields-2.c:18:3-18:15) + < write with [mhp:{created={[main, t_fun@85-distribute-fields-2.c:24:3-24:40]}}, threadflag:(MT mode:Multithreaded (main), bool:true), thread:[main]] (conf. 110) (exp: & t.s) (85-distribute-fields-2.c:26:3-26:11) --- - > write with [mhp:{tid=[main, t_fun@85-distribute-fields-2.c:24:3-24:40#⊤]}, thread:[main, t_fun@85-distribute-fields-2.c:24:3-24:40#⊤]] (conf. 110) (exp: & t.s.data) (85-distribute-fields-2.c:18:3-18:15) - > write with [mhp:{tid=[main]; created={[main, t_fun@85-distribute-fields-2.c:24:3-24:40#⊤]}}, thread:[main]] (conf. 110) (exp: & t.s) (85-distribute-fields-2.c:26:3-26:11) + > write with [mhp:{tid=[main, t_fun@85-distribute-fields-2.c:24:3-24:40#⊤]}, threadflag:(MT mode:Multithreaded (other), bool:true), thread:[main, t_fun@85-distribute-fields-2.c:24:3-24:40#⊤]] (conf. 110) (exp: & t.s.data) (85-distribute-fields-2.c:18:3-18:15) + > write with [mhp:{tid=[main]; created={[main, t_fun@85-distribute-fields-2.c:24:3-24:40#⊤]}}, threadflag:(MT mode:Multithreaded (main), bool:true), thread:[main]] (conf. 110) (exp: & t.s) (85-distribute-fields-2.c:26:3-26:11) 10c10 - < write with [mhp:{created={[main, t_fun@85-distribute-fields-2.c:24:3-24:40]}}, thread:[main]] (conf. 110) (exp: & t.s) (85-distribute-fields-2.c:26:3-26:11) + < write with [mhp:{created={[main, t_fun@85-distribute-fields-2.c:24:3-24:40]}}, threadflag:(MT mode:Multithreaded (main), bool:true), thread:[main]] (conf. 110) (exp: & t.s) (85-distribute-fields-2.c:26:3-26:11) --- - > write with [mhp:{tid=[main]; created={[main, t_fun@85-distribute-fields-2.c:24:3-24:40#⊤]}}, thread:[main]] (conf. 110) (exp: & t.s) (85-distribute-fields-2.c:26:3-26:11) + > write with [mhp:{tid=[main]; created={[main, t_fun@85-distribute-fields-2.c:24:3-24:40#⊤]}}, threadflag:(MT mode:Multithreaded (main), bool:true), thread:[main]] (conf. 110) (exp: & t.s) (85-distribute-fields-2.c:26:3-26:11) [1] diff --git a/tests/regression/04-mutex/86-distribute-fields-3.t b/tests/regression/04-mutex/86-distribute-fields-3.t index c5ebd6d28a..6819a98396 100644 --- a/tests/regression/04-mutex/86-distribute-fields-3.t +++ b/tests/regression/04-mutex/86-distribute-fields-3.t @@ -1,14 +1,14 @@ $ goblint --enable warn.deterministic --enable allglobs 86-distribute-fields-3.c 2>&1 | tee default-output.txt [Warning][Race] Memory location t.s.data (race with conf. 110): (86-distribute-fields-3.c:15:10-15:11) - write with thread:[main, t_fun@86-distribute-fields-3.c:24:3-24:40] (conf. 110) (exp: & t.s.data) (86-distribute-fields-3.c:18:3-18:15) - write with [mhp:{created={[main, t_fun@86-distribute-fields-3.c:24:3-24:40]}}, thread:[main]] (conf. 110) (exp: & t) (86-distribute-fields-3.c:26:3-26:9) + write with [threadflag:(MT mode:Multithreaded (other), bool:true), thread:[main, t_fun@86-distribute-fields-3.c:24:3-24:40]] (conf. 110) (exp: & t.s.data) (86-distribute-fields-3.c:18:3-18:15) + write with [mhp:{created={[main, t_fun@86-distribute-fields-3.c:24:3-24:40]}}, threadflag:(MT mode:Multithreaded (main), bool:true), thread:[main]] (conf. 110) (exp: & t) (86-distribute-fields-3.c:26:3-26:9) [Info][Race] Memory locations race summary: safe: 1 vulnerable: 0 unsafe: 1 total memory locations: 2 [Success][Race] Memory location t (safe): (86-distribute-fields-3.c:15:10-15:11) - write with [mhp:{created={[main, t_fun@86-distribute-fields-3.c:24:3-24:40]}}, thread:[main]] (conf. 110) (exp: & t) (86-distribute-fields-3.c:26:3-26:9) + write with [mhp:{created={[main, t_fun@86-distribute-fields-3.c:24:3-24:40]}}, threadflag:(MT mode:Multithreaded (main), bool:true), thread:[main]] (conf. 110) (exp: & t) (86-distribute-fields-3.c:26:3-26:9) [Info][Deadcode] Logical lines of code (LLoC) summary: live: 8 dead: 0 @@ -18,13 +18,13 @@ $ diff default-output.txt full-output.txt 2,3c2,3 - < write with thread:[main, t_fun@86-distribute-fields-3.c:24:3-24:40] (conf. 110) (exp: & t.s.data) (86-distribute-fields-3.c:18:3-18:15) - < write with [mhp:{created={[main, t_fun@86-distribute-fields-3.c:24:3-24:40]}}, thread:[main]] (conf. 110) (exp: & t) (86-distribute-fields-3.c:26:3-26:9) + < write with [threadflag:(MT mode:Multithreaded (other), bool:true), thread:[main, t_fun@86-distribute-fields-3.c:24:3-24:40]] (conf. 110) (exp: & t.s.data) (86-distribute-fields-3.c:18:3-18:15) + < write with [mhp:{created={[main, t_fun@86-distribute-fields-3.c:24:3-24:40]}}, threadflag:(MT mode:Multithreaded (main), bool:true), thread:[main]] (conf. 110) (exp: & t) (86-distribute-fields-3.c:26:3-26:9) --- - > write with [mhp:{tid=[main, t_fun@86-distribute-fields-3.c:24:3-24:40#⊤]}, thread:[main, t_fun@86-distribute-fields-3.c:24:3-24:40#⊤]] (conf. 110) (exp: & t.s.data) (86-distribute-fields-3.c:18:3-18:15) - > write with [mhp:{tid=[main]; created={[main, t_fun@86-distribute-fields-3.c:24:3-24:40#⊤]}}, thread:[main]] (conf. 110) (exp: & t) (86-distribute-fields-3.c:26:3-26:9) + > write with [mhp:{tid=[main, t_fun@86-distribute-fields-3.c:24:3-24:40#⊤]}, threadflag:(MT mode:Multithreaded (other), bool:true), thread:[main, t_fun@86-distribute-fields-3.c:24:3-24:40#⊤]] (conf. 110) (exp: & t.s.data) (86-distribute-fields-3.c:18:3-18:15) + > write with [mhp:{tid=[main]; created={[main, t_fun@86-distribute-fields-3.c:24:3-24:40#⊤]}}, threadflag:(MT mode:Multithreaded (main), bool:true), thread:[main]] (conf. 110) (exp: & t) (86-distribute-fields-3.c:26:3-26:9) 10c10 - < write with [mhp:{created={[main, t_fun@86-distribute-fields-3.c:24:3-24:40]}}, thread:[main]] (conf. 110) (exp: & t) (86-distribute-fields-3.c:26:3-26:9) + < write with [mhp:{created={[main, t_fun@86-distribute-fields-3.c:24:3-24:40]}}, threadflag:(MT mode:Multithreaded (main), bool:true), thread:[main]] (conf. 110) (exp: & t) (86-distribute-fields-3.c:26:3-26:9) --- - > write with [mhp:{tid=[main]; created={[main, t_fun@86-distribute-fields-3.c:24:3-24:40#⊤]}}, thread:[main]] (conf. 110) (exp: & t) (86-distribute-fields-3.c:26:3-26:9) + > write with [mhp:{tid=[main]; created={[main, t_fun@86-distribute-fields-3.c:24:3-24:40#⊤]}}, threadflag:(MT mode:Multithreaded (main), bool:true), thread:[main]] (conf. 110) (exp: & t) (86-distribute-fields-3.c:26:3-26:9) [1] diff --git a/tests/regression/04-mutex/87-distribute-fields-4.t b/tests/regression/04-mutex/87-distribute-fields-4.t index 2d3dfb6b7c..713bc79679 100644 --- a/tests/regression/04-mutex/87-distribute-fields-4.t +++ b/tests/regression/04-mutex/87-distribute-fields-4.t @@ -1,7 +1,7 @@ $ goblint --enable warn.deterministic --enable allglobs 87-distribute-fields-4.c 2>&1 | tee default-output.txt [Warning][Race] Memory location s (race with conf. 110): (87-distribute-fields-4.c:9:10-9:11) - write with thread:[main, t_fun@87-distribute-fields-4.c:19:3-19:40] (conf. 110) (exp: & s) (87-distribute-fields-4.c:13:3-13:9) - write with [mhp:{created={[main, t_fun@87-distribute-fields-4.c:19:3-19:40]}}, thread:[main]] (conf. 110) (exp: & s) (87-distribute-fields-4.c:21:3-21:9) + write with [threadflag:(MT mode:Multithreaded (other), bool:true), thread:[main, t_fun@87-distribute-fields-4.c:19:3-19:40]] (conf. 110) (exp: & s) (87-distribute-fields-4.c:13:3-13:9) + write with [mhp:{created={[main, t_fun@87-distribute-fields-4.c:19:3-19:40]}}, threadflag:(MT mode:Multithreaded (main), bool:true), thread:[main]] (conf. 110) (exp: & s) (87-distribute-fields-4.c:21:3-21:9) [Info][Race] Memory locations race summary: safe: 0 vulnerable: 0 @@ -16,9 +16,9 @@ $ diff default-output.txt full-output.txt 2,3c2,3 - < write with thread:[main, t_fun@87-distribute-fields-4.c:19:3-19:40] (conf. 110) (exp: & s) (87-distribute-fields-4.c:13:3-13:9) - < write with [mhp:{created={[main, t_fun@87-distribute-fields-4.c:19:3-19:40]}}, thread:[main]] (conf. 110) (exp: & s) (87-distribute-fields-4.c:21:3-21:9) + < write with [threadflag:(MT mode:Multithreaded (other), bool:true), thread:[main, t_fun@87-distribute-fields-4.c:19:3-19:40]] (conf. 110) (exp: & s) (87-distribute-fields-4.c:13:3-13:9) + < write with [mhp:{created={[main, t_fun@87-distribute-fields-4.c:19:3-19:40]}}, threadflag:(MT mode:Multithreaded (main), bool:true), thread:[main]] (conf. 110) (exp: & s) (87-distribute-fields-4.c:21:3-21:9) --- - > write with [mhp:{tid=[main, t_fun@87-distribute-fields-4.c:19:3-19:40#⊤]}, thread:[main, t_fun@87-distribute-fields-4.c:19:3-19:40#⊤]] (conf. 110) (exp: & s) (87-distribute-fields-4.c:13:3-13:9) - > write with [mhp:{tid=[main]; created={[main, t_fun@87-distribute-fields-4.c:19:3-19:40#⊤]}}, thread:[main]] (conf. 110) (exp: & s) (87-distribute-fields-4.c:21:3-21:9) + > write with [mhp:{tid=[main, t_fun@87-distribute-fields-4.c:19:3-19:40#⊤]}, threadflag:(MT mode:Multithreaded (other), bool:true), thread:[main, t_fun@87-distribute-fields-4.c:19:3-19:40#⊤]] (conf. 110) (exp: & s) (87-distribute-fields-4.c:13:3-13:9) + > write with [mhp:{tid=[main]; created={[main, t_fun@87-distribute-fields-4.c:19:3-19:40#⊤]}}, threadflag:(MT mode:Multithreaded (main), bool:true), thread:[main]] (conf. 110) (exp: & s) (87-distribute-fields-4.c:21:3-21:9) [1] diff --git a/tests/regression/04-mutex/88-distribute-fields-5.t b/tests/regression/04-mutex/88-distribute-fields-5.t index 0afdc729ef..eba8db4d5a 100644 --- a/tests/regression/04-mutex/88-distribute-fields-5.t +++ b/tests/regression/04-mutex/88-distribute-fields-5.t @@ -1,7 +1,7 @@ $ goblint --enable warn.deterministic --enable allglobs 88-distribute-fields-5.c 2>&1 | tee default-output.txt [Warning][Race] Memory location t.s (race with conf. 110): (88-distribute-fields-5.c:15:10-15:11) - write with thread:[main, t_fun@88-distribute-fields-5.c:25:3-25:40] (conf. 110) (exp: & t.s) (88-distribute-fields-5.c:19:3-19:11) - write with [mhp:{created={[main, t_fun@88-distribute-fields-5.c:25:3-25:40]}}, thread:[main]] (conf. 110) (exp: & t.s) (88-distribute-fields-5.c:27:3-27:11) + write with [threadflag:(MT mode:Multithreaded (other), bool:true), thread:[main, t_fun@88-distribute-fields-5.c:25:3-25:40]] (conf. 110) (exp: & t.s) (88-distribute-fields-5.c:19:3-19:11) + write with [mhp:{created={[main, t_fun@88-distribute-fields-5.c:25:3-25:40]}}, threadflag:(MT mode:Multithreaded (main), bool:true), thread:[main]] (conf. 110) (exp: & t.s) (88-distribute-fields-5.c:27:3-27:11) [Info][Race] Memory locations race summary: safe: 0 vulnerable: 0 @@ -16,9 +16,9 @@ $ diff default-output.txt full-output.txt 2,3c2,3 - < write with thread:[main, t_fun@88-distribute-fields-5.c:25:3-25:40] (conf. 110) (exp: & t.s) (88-distribute-fields-5.c:19:3-19:11) - < write with [mhp:{created={[main, t_fun@88-distribute-fields-5.c:25:3-25:40]}}, thread:[main]] (conf. 110) (exp: & t.s) (88-distribute-fields-5.c:27:3-27:11) + < write with [threadflag:(MT mode:Multithreaded (other), bool:true), thread:[main, t_fun@88-distribute-fields-5.c:25:3-25:40]] (conf. 110) (exp: & t.s) (88-distribute-fields-5.c:19:3-19:11) + < write with [mhp:{created={[main, t_fun@88-distribute-fields-5.c:25:3-25:40]}}, threadflag:(MT mode:Multithreaded (main), bool:true), thread:[main]] (conf. 110) (exp: & t.s) (88-distribute-fields-5.c:27:3-27:11) --- - > write with [mhp:{tid=[main, t_fun@88-distribute-fields-5.c:25:3-25:40#⊤]}, thread:[main, t_fun@88-distribute-fields-5.c:25:3-25:40#⊤]] (conf. 110) (exp: & t.s) (88-distribute-fields-5.c:19:3-19:11) - > write with [mhp:{tid=[main]; created={[main, t_fun@88-distribute-fields-5.c:25:3-25:40#⊤]}}, thread:[main]] (conf. 110) (exp: & t.s) (88-distribute-fields-5.c:27:3-27:11) + > write with [mhp:{tid=[main, t_fun@88-distribute-fields-5.c:25:3-25:40#⊤]}, threadflag:(MT mode:Multithreaded (other), bool:true), thread:[main, t_fun@88-distribute-fields-5.c:25:3-25:40#⊤]] (conf. 110) (exp: & t.s) (88-distribute-fields-5.c:19:3-19:11) + > write with [mhp:{tid=[main]; created={[main, t_fun@88-distribute-fields-5.c:25:3-25:40#⊤]}}, threadflag:(MT mode:Multithreaded (main), bool:true), thread:[main]] (conf. 110) (exp: & t.s) (88-distribute-fields-5.c:27:3-27:11) [1] diff --git a/tests/regression/04-mutex/89-distribute-fields-6.t b/tests/regression/04-mutex/89-distribute-fields-6.t index 20533099de..0bad7aba3f 100644 --- a/tests/regression/04-mutex/89-distribute-fields-6.t +++ b/tests/regression/04-mutex/89-distribute-fields-6.t @@ -1,7 +1,7 @@ $ goblint --enable warn.deterministic --enable allglobs 89-distribute-fields-6.c 2>&1 | tee default-output.txt [Warning][Race] Memory location t (race with conf. 110): (89-distribute-fields-6.c:15:10-15:11) - write with thread:[main, t_fun@89-distribute-fields-6.c:25:3-25:40] (conf. 110) (exp: & t) (89-distribute-fields-6.c:19:3-19:9) - write with [mhp:{created={[main, t_fun@89-distribute-fields-6.c:25:3-25:40]}}, thread:[main]] (conf. 110) (exp: & t) (89-distribute-fields-6.c:27:3-27:9) + write with [threadflag:(MT mode:Multithreaded (other), bool:true), thread:[main, t_fun@89-distribute-fields-6.c:25:3-25:40]] (conf. 110) (exp: & t) (89-distribute-fields-6.c:19:3-19:9) + write with [mhp:{created={[main, t_fun@89-distribute-fields-6.c:25:3-25:40]}}, threadflag:(MT mode:Multithreaded (main), bool:true), thread:[main]] (conf. 110) (exp: & t) (89-distribute-fields-6.c:27:3-27:9) [Info][Race] Memory locations race summary: safe: 0 vulnerable: 0 @@ -16,9 +16,9 @@ $ diff default-output.txt full-output.txt 2,3c2,3 - < write with thread:[main, t_fun@89-distribute-fields-6.c:25:3-25:40] (conf. 110) (exp: & t) (89-distribute-fields-6.c:19:3-19:9) - < write with [mhp:{created={[main, t_fun@89-distribute-fields-6.c:25:3-25:40]}}, thread:[main]] (conf. 110) (exp: & t) (89-distribute-fields-6.c:27:3-27:9) + < write with [threadflag:(MT mode:Multithreaded (other), bool:true), thread:[main, t_fun@89-distribute-fields-6.c:25:3-25:40]] (conf. 110) (exp: & t) (89-distribute-fields-6.c:19:3-19:9) + < write with [mhp:{created={[main, t_fun@89-distribute-fields-6.c:25:3-25:40]}}, threadflag:(MT mode:Multithreaded (main), bool:true), thread:[main]] (conf. 110) (exp: & t) (89-distribute-fields-6.c:27:3-27:9) --- - > write with [mhp:{tid=[main, t_fun@89-distribute-fields-6.c:25:3-25:40#⊤]}, thread:[main, t_fun@89-distribute-fields-6.c:25:3-25:40#⊤]] (conf. 110) (exp: & t) (89-distribute-fields-6.c:19:3-19:9) - > write with [mhp:{tid=[main]; created={[main, t_fun@89-distribute-fields-6.c:25:3-25:40#⊤]}}, thread:[main]] (conf. 110) (exp: & t) (89-distribute-fields-6.c:27:3-27:9) + > write with [mhp:{tid=[main, t_fun@89-distribute-fields-6.c:25:3-25:40#⊤]}, threadflag:(MT mode:Multithreaded (other), bool:true), thread:[main, t_fun@89-distribute-fields-6.c:25:3-25:40#⊤]] (conf. 110) (exp: & t) (89-distribute-fields-6.c:19:3-19:9) + > write with [mhp:{tid=[main]; created={[main, t_fun@89-distribute-fields-6.c:25:3-25:40#⊤]}}, threadflag:(MT mode:Multithreaded (main), bool:true), thread:[main]] (conf. 110) (exp: & t) (89-distribute-fields-6.c:27:3-27:9) [1] diff --git a/tests/regression/04-mutex/90-distribute-fields-type-1.t b/tests/regression/04-mutex/90-distribute-fields-type-1.t index 1a5c739e9c..cc40a3cf4c 100644 --- a/tests/regression/04-mutex/90-distribute-fields-type-1.t +++ b/tests/regression/04-mutex/90-distribute-fields-type-1.t @@ -2,17 +2,17 @@ [Warning][Behavior > Undefined > NullPointerDereference][CWE-476] May dereference NULL pointer (90-distribute-fields-type-1.c:31:3-31:20) [Warning][Behavior > Undefined > NullPointerDereference][CWE-476] May dereference NULL pointer (90-distribute-fields-type-1.c:39:3-39:17) [Warning][Race] Memory location (struct T).s.field (race with conf. 100): - write with thread:[main, t_fun@90-distribute-fields-type-1.c:37:3-37:40] (conf. 100) (exp: & tmp->field) (90-distribute-fields-type-1.c:31:3-31:20) - write with [mhp:{created={[main, t_fun@90-distribute-fields-type-1.c:37:3-37:40]}}, thread:[main]] (conf. 100) (exp: & tmp->s) (90-distribute-fields-type-1.c:39:3-39:17) + write with [threadflag:(MT mode:Multithreaded (other), bool:true), thread:[main, t_fun@90-distribute-fields-type-1.c:37:3-37:40]] (conf. 100) (exp: & tmp->field) (90-distribute-fields-type-1.c:31:3-31:20) + write with [mhp:{created={[main, t_fun@90-distribute-fields-type-1.c:37:3-37:40]}}, threadflag:(MT mode:Multithreaded (main), bool:true), thread:[main]] (conf. 100) (exp: & tmp->s) (90-distribute-fields-type-1.c:39:3-39:17) [Info][Race] Memory locations race summary: safe: 2 vulnerable: 0 unsafe: 1 total memory locations: 3 [Success][Race] Memory location (struct S).field (safe): - write with thread:[main, t_fun@90-distribute-fields-type-1.c:37:3-37:40] (conf. 100) (exp: & tmp->field) (90-distribute-fields-type-1.c:31:3-31:20) + write with [threadflag:(MT mode:Multithreaded (other), bool:true), thread:[main, t_fun@90-distribute-fields-type-1.c:37:3-37:40]] (conf. 100) (exp: & tmp->field) (90-distribute-fields-type-1.c:31:3-31:20) [Success][Race] Memory location (struct T).s (safe): - write with [mhp:{created={[main, t_fun@90-distribute-fields-type-1.c:37:3-37:40]}}, thread:[main]] (conf. 100) (exp: & tmp->s) (90-distribute-fields-type-1.c:39:3-39:17) + write with [mhp:{created={[main, t_fun@90-distribute-fields-type-1.c:37:3-37:40]}}, threadflag:(MT mode:Multithreaded (main), bool:true), thread:[main]] (conf. 100) (exp: & tmp->s) (90-distribute-fields-type-1.c:39:3-39:17) [Info][Deadcode] Logical lines of code (LLoC) summary: live: 7 dead: 0 @@ -31,17 +31,17 @@ $ diff default-output.txt full-output.txt 4,5c4,5 - < write with thread:[main, t_fun@90-distribute-fields-type-1.c:37:3-37:40] (conf. 100) (exp: & tmp->field) (90-distribute-fields-type-1.c:31:3-31:20) - < write with [mhp:{created={[main, t_fun@90-distribute-fields-type-1.c:37:3-37:40]}}, thread:[main]] (conf. 100) (exp: & tmp->s) (90-distribute-fields-type-1.c:39:3-39:17) + < write with [threadflag:(MT mode:Multithreaded (other), bool:true), thread:[main, t_fun@90-distribute-fields-type-1.c:37:3-37:40]] (conf. 100) (exp: & tmp->field) (90-distribute-fields-type-1.c:31:3-31:20) + < write with [mhp:{created={[main, t_fun@90-distribute-fields-type-1.c:37:3-37:40]}}, threadflag:(MT mode:Multithreaded (main), bool:true), thread:[main]] (conf. 100) (exp: & tmp->s) (90-distribute-fields-type-1.c:39:3-39:17) --- - > write with [mhp:{tid=[main, t_fun@90-distribute-fields-type-1.c:37:3-37:40#⊤]}, thread:[main, t_fun@90-distribute-fields-type-1.c:37:3-37:40#⊤]] (conf. 100) (exp: & tmp->field) (90-distribute-fields-type-1.c:31:3-31:20) - > write with [mhp:{tid=[main]; created={[main, t_fun@90-distribute-fields-type-1.c:37:3-37:40#⊤]}}, thread:[main]] (conf. 100) (exp: & tmp->s) (90-distribute-fields-type-1.c:39:3-39:17) + > write with [mhp:{tid=[main, t_fun@90-distribute-fields-type-1.c:37:3-37:40#⊤]}, threadflag:(MT mode:Multithreaded (other), bool:true), thread:[main, t_fun@90-distribute-fields-type-1.c:37:3-37:40#⊤]] (conf. 100) (exp: & tmp->field) (90-distribute-fields-type-1.c:31:3-31:20) + > write with [mhp:{tid=[main]; created={[main, t_fun@90-distribute-fields-type-1.c:37:3-37:40#⊤]}}, threadflag:(MT mode:Multithreaded (main), bool:true), thread:[main]] (conf. 100) (exp: & tmp->s) (90-distribute-fields-type-1.c:39:3-39:17) 12c12 - < write with thread:[main, t_fun@90-distribute-fields-type-1.c:37:3-37:40] (conf. 100) (exp: & tmp->field) (90-distribute-fields-type-1.c:31:3-31:20) + < write with [threadflag:(MT mode:Multithreaded (other), bool:true), thread:[main, t_fun@90-distribute-fields-type-1.c:37:3-37:40]] (conf. 100) (exp: & tmp->field) (90-distribute-fields-type-1.c:31:3-31:20) --- - > write with [mhp:{tid=[main, t_fun@90-distribute-fields-type-1.c:37:3-37:40#⊤]}, thread:[main, t_fun@90-distribute-fields-type-1.c:37:3-37:40#⊤]] (conf. 100) (exp: & tmp->field) (90-distribute-fields-type-1.c:31:3-31:20) + > write with [mhp:{tid=[main, t_fun@90-distribute-fields-type-1.c:37:3-37:40#⊤]}, threadflag:(MT mode:Multithreaded (other), bool:true), thread:[main, t_fun@90-distribute-fields-type-1.c:37:3-37:40#⊤]] (conf. 100) (exp: & tmp->field) (90-distribute-fields-type-1.c:31:3-31:20) 14c14 - < write with [mhp:{created={[main, t_fun@90-distribute-fields-type-1.c:37:3-37:40]}}, thread:[main]] (conf. 100) (exp: & tmp->s) (90-distribute-fields-type-1.c:39:3-39:17) + < write with [mhp:{created={[main, t_fun@90-distribute-fields-type-1.c:37:3-37:40]}}, threadflag:(MT mode:Multithreaded (main), bool:true), thread:[main]] (conf. 100) (exp: & tmp->s) (90-distribute-fields-type-1.c:39:3-39:17) --- - > write with [mhp:{tid=[main]; created={[main, t_fun@90-distribute-fields-type-1.c:37:3-37:40#⊤]}}, thread:[main]] (conf. 100) (exp: & tmp->s) (90-distribute-fields-type-1.c:39:3-39:17) + > write with [mhp:{tid=[main]; created={[main, t_fun@90-distribute-fields-type-1.c:37:3-37:40#⊤]}}, threadflag:(MT mode:Multithreaded (main), bool:true), thread:[main]] (conf. 100) (exp: & tmp->s) (90-distribute-fields-type-1.c:39:3-39:17) [1] diff --git a/tests/regression/04-mutex/91-distribute-fields-type-2.t b/tests/regression/04-mutex/91-distribute-fields-type-2.t index e22b21d2bd..e3a861adc0 100644 --- a/tests/regression/04-mutex/91-distribute-fields-type-2.t +++ b/tests/regression/04-mutex/91-distribute-fields-type-2.t @@ -2,17 +2,17 @@ [Warning][Behavior > Undefined > NullPointerDereference][CWE-476] May dereference NULL pointer (91-distribute-fields-type-2.c:32:3-32:17) [Warning][Behavior > Undefined > NullPointerDereference][CWE-476] May dereference NULL pointer (91-distribute-fields-type-2.c:40:3-40:17) [Warning][Race] Memory location (struct T).s (race with conf. 100): - write with thread:[main, t_fun@91-distribute-fields-type-2.c:38:3-38:40] (conf. 100) (exp: & *tmp) (91-distribute-fields-type-2.c:32:3-32:17) - write with [mhp:{created={[main, t_fun@91-distribute-fields-type-2.c:38:3-38:40]}}, thread:[main]] (conf. 100) (exp: & *tmp) (91-distribute-fields-type-2.c:40:3-40:17) + write with [threadflag:(MT mode:Multithreaded (other), bool:true), thread:[main, t_fun@91-distribute-fields-type-2.c:38:3-38:40]] (conf. 100) (exp: & *tmp) (91-distribute-fields-type-2.c:32:3-32:17) + write with [mhp:{created={[main, t_fun@91-distribute-fields-type-2.c:38:3-38:40]}}, threadflag:(MT mode:Multithreaded (main), bool:true), thread:[main]] (conf. 100) (exp: & *tmp) (91-distribute-fields-type-2.c:40:3-40:17) [Info][Race] Memory locations race summary: safe: 2 vulnerable: 0 unsafe: 1 total memory locations: 3 [Success][Race] Memory location (struct S) (safe): - write with thread:[main, t_fun@91-distribute-fields-type-2.c:38:3-38:40] (conf. 100) (exp: & *tmp) (91-distribute-fields-type-2.c:32:3-32:17) + write with [threadflag:(MT mode:Multithreaded (other), bool:true), thread:[main, t_fun@91-distribute-fields-type-2.c:38:3-38:40]] (conf. 100) (exp: & *tmp) (91-distribute-fields-type-2.c:32:3-32:17) [Success][Race] Memory location (struct T) (safe): - write with [mhp:{created={[main, t_fun@91-distribute-fields-type-2.c:38:3-38:40]}}, thread:[main]] (conf. 100) (exp: & *tmp) (91-distribute-fields-type-2.c:40:3-40:17) + write with [mhp:{created={[main, t_fun@91-distribute-fields-type-2.c:38:3-38:40]}}, threadflag:(MT mode:Multithreaded (main), bool:true), thread:[main]] (conf. 100) (exp: & *tmp) (91-distribute-fields-type-2.c:40:3-40:17) [Info][Deadcode] Logical lines of code (LLoC) summary: live: 7 dead: 0 @@ -31,17 +31,17 @@ $ diff default-output.txt full-output.txt 4,5c4,5 - < write with thread:[main, t_fun@91-distribute-fields-type-2.c:38:3-38:40] (conf. 100) (exp: & *tmp) (91-distribute-fields-type-2.c:32:3-32:17) - < write with [mhp:{created={[main, t_fun@91-distribute-fields-type-2.c:38:3-38:40]}}, thread:[main]] (conf. 100) (exp: & *tmp) (91-distribute-fields-type-2.c:40:3-40:17) + < write with [threadflag:(MT mode:Multithreaded (other), bool:true), thread:[main, t_fun@91-distribute-fields-type-2.c:38:3-38:40]] (conf. 100) (exp: & *tmp) (91-distribute-fields-type-2.c:32:3-32:17) + < write with [mhp:{created={[main, t_fun@91-distribute-fields-type-2.c:38:3-38:40]}}, threadflag:(MT mode:Multithreaded (main), bool:true), thread:[main]] (conf. 100) (exp: & *tmp) (91-distribute-fields-type-2.c:40:3-40:17) --- - > write with [mhp:{tid=[main, t_fun@91-distribute-fields-type-2.c:38:3-38:40#⊤]}, thread:[main, t_fun@91-distribute-fields-type-2.c:38:3-38:40#⊤]] (conf. 100) (exp: & *tmp) (91-distribute-fields-type-2.c:32:3-32:17) - > write with [mhp:{tid=[main]; created={[main, t_fun@91-distribute-fields-type-2.c:38:3-38:40#⊤]}}, thread:[main]] (conf. 100) (exp: & *tmp) (91-distribute-fields-type-2.c:40:3-40:17) + > write with [mhp:{tid=[main, t_fun@91-distribute-fields-type-2.c:38:3-38:40#⊤]}, threadflag:(MT mode:Multithreaded (other), bool:true), thread:[main, t_fun@91-distribute-fields-type-2.c:38:3-38:40#⊤]] (conf. 100) (exp: & *tmp) (91-distribute-fields-type-2.c:32:3-32:17) + > write with [mhp:{tid=[main]; created={[main, t_fun@91-distribute-fields-type-2.c:38:3-38:40#⊤]}}, threadflag:(MT mode:Multithreaded (main), bool:true), thread:[main]] (conf. 100) (exp: & *tmp) (91-distribute-fields-type-2.c:40:3-40:17) 12c12 - < write with thread:[main, t_fun@91-distribute-fields-type-2.c:38:3-38:40] (conf. 100) (exp: & *tmp) (91-distribute-fields-type-2.c:32:3-32:17) + < write with [threadflag:(MT mode:Multithreaded (other), bool:true), thread:[main, t_fun@91-distribute-fields-type-2.c:38:3-38:40]] (conf. 100) (exp: & *tmp) (91-distribute-fields-type-2.c:32:3-32:17) --- - > write with [mhp:{tid=[main, t_fun@91-distribute-fields-type-2.c:38:3-38:40#⊤]}, thread:[main, t_fun@91-distribute-fields-type-2.c:38:3-38:40#⊤]] (conf. 100) (exp: & *tmp) (91-distribute-fields-type-2.c:32:3-32:17) + > write with [mhp:{tid=[main, t_fun@91-distribute-fields-type-2.c:38:3-38:40#⊤]}, threadflag:(MT mode:Multithreaded (other), bool:true), thread:[main, t_fun@91-distribute-fields-type-2.c:38:3-38:40#⊤]] (conf. 100) (exp: & *tmp) (91-distribute-fields-type-2.c:32:3-32:17) 14c14 - < write with [mhp:{created={[main, t_fun@91-distribute-fields-type-2.c:38:3-38:40]}}, thread:[main]] (conf. 100) (exp: & *tmp) (91-distribute-fields-type-2.c:40:3-40:17) + < write with [mhp:{created={[main, t_fun@91-distribute-fields-type-2.c:38:3-38:40]}}, threadflag:(MT mode:Multithreaded (main), bool:true), thread:[main]] (conf. 100) (exp: & *tmp) (91-distribute-fields-type-2.c:40:3-40:17) --- - > write with [mhp:{tid=[main]; created={[main, t_fun@91-distribute-fields-type-2.c:38:3-38:40#⊤]}}, thread:[main]] (conf. 100) (exp: & *tmp) (91-distribute-fields-type-2.c:40:3-40:17) + > write with [mhp:{tid=[main]; created={[main, t_fun@91-distribute-fields-type-2.c:38:3-38:40#⊤]}}, threadflag:(MT mode:Multithreaded (main), bool:true), thread:[main]] (conf. 100) (exp: & *tmp) (91-distribute-fields-type-2.c:40:3-40:17) [1] diff --git a/tests/regression/04-mutex/92-distribute-fields-type-deep.t b/tests/regression/04-mutex/92-distribute-fields-type-deep.t index d754ded21b..a0663678dd 100644 --- a/tests/regression/04-mutex/92-distribute-fields-type-deep.t +++ b/tests/regression/04-mutex/92-distribute-fields-type-deep.t @@ -2,17 +2,17 @@ [Warning][Behavior > Undefined > NullPointerDereference][CWE-476] May dereference NULL pointer (92-distribute-fields-type-deep.c:36:3-36:20) [Warning][Behavior > Undefined > NullPointerDereference][CWE-476] May dereference NULL pointer (92-distribute-fields-type-deep.c:44:3-44:17) [Warning][Race] Memory location (struct U).t.s.field (race with conf. 100): - write with thread:[main, t_fun@92-distribute-fields-type-deep.c:42:3-42:40] (conf. 100) (exp: & tmp->field) (92-distribute-fields-type-deep.c:36:3-36:20) - write with [mhp:{created={[main, t_fun@92-distribute-fields-type-deep.c:42:3-42:40]}}, thread:[main]] (conf. 100) (exp: & tmp->t) (92-distribute-fields-type-deep.c:44:3-44:17) + write with [threadflag:(MT mode:Multithreaded (other), bool:true), thread:[main, t_fun@92-distribute-fields-type-deep.c:42:3-42:40]] (conf. 100) (exp: & tmp->field) (92-distribute-fields-type-deep.c:36:3-36:20) + write with [mhp:{created={[main, t_fun@92-distribute-fields-type-deep.c:42:3-42:40]}}, threadflag:(MT mode:Multithreaded (main), bool:true), thread:[main]] (conf. 100) (exp: & tmp->t) (92-distribute-fields-type-deep.c:44:3-44:17) [Info][Race] Memory locations race summary: safe: 2 vulnerable: 0 unsafe: 1 total memory locations: 3 [Success][Race] Memory location (struct S).field (safe): - write with thread:[main, t_fun@92-distribute-fields-type-deep.c:42:3-42:40] (conf. 100) (exp: & tmp->field) (92-distribute-fields-type-deep.c:36:3-36:20) + write with [threadflag:(MT mode:Multithreaded (other), bool:true), thread:[main, t_fun@92-distribute-fields-type-deep.c:42:3-42:40]] (conf. 100) (exp: & tmp->field) (92-distribute-fields-type-deep.c:36:3-36:20) [Success][Race] Memory location (struct U).t (safe): - write with [mhp:{created={[main, t_fun@92-distribute-fields-type-deep.c:42:3-42:40]}}, thread:[main]] (conf. 100) (exp: & tmp->t) (92-distribute-fields-type-deep.c:44:3-44:17) + write with [mhp:{created={[main, t_fun@92-distribute-fields-type-deep.c:42:3-42:40]}}, threadflag:(MT mode:Multithreaded (main), bool:true), thread:[main]] (conf. 100) (exp: & tmp->t) (92-distribute-fields-type-deep.c:44:3-44:17) [Info][Deadcode] Logical lines of code (LLoC) summary: live: 7 dead: 0 @@ -31,17 +31,17 @@ $ diff default-output.txt full-output.txt 4,5c4,5 - < write with thread:[main, t_fun@92-distribute-fields-type-deep.c:42:3-42:40] (conf. 100) (exp: & tmp->field) (92-distribute-fields-type-deep.c:36:3-36:20) - < write with [mhp:{created={[main, t_fun@92-distribute-fields-type-deep.c:42:3-42:40]}}, thread:[main]] (conf. 100) (exp: & tmp->t) (92-distribute-fields-type-deep.c:44:3-44:17) + < write with [threadflag:(MT mode:Multithreaded (other), bool:true), thread:[main, t_fun@92-distribute-fields-type-deep.c:42:3-42:40]] (conf. 100) (exp: & tmp->field) (92-distribute-fields-type-deep.c:36:3-36:20) + < write with [mhp:{created={[main, t_fun@92-distribute-fields-type-deep.c:42:3-42:40]}}, threadflag:(MT mode:Multithreaded (main), bool:true), thread:[main]] (conf. 100) (exp: & tmp->t) (92-distribute-fields-type-deep.c:44:3-44:17) --- - > write with [mhp:{tid=[main, t_fun@92-distribute-fields-type-deep.c:42:3-42:40#⊤]}, thread:[main, t_fun@92-distribute-fields-type-deep.c:42:3-42:40#⊤]] (conf. 100) (exp: & tmp->field) (92-distribute-fields-type-deep.c:36:3-36:20) - > write with [mhp:{tid=[main]; created={[main, t_fun@92-distribute-fields-type-deep.c:42:3-42:40#⊤]}}, thread:[main]] (conf. 100) (exp: & tmp->t) (92-distribute-fields-type-deep.c:44:3-44:17) + > write with [mhp:{tid=[main, t_fun@92-distribute-fields-type-deep.c:42:3-42:40#⊤]}, threadflag:(MT mode:Multithreaded (other), bool:true), thread:[main, t_fun@92-distribute-fields-type-deep.c:42:3-42:40#⊤]] (conf. 100) (exp: & tmp->field) (92-distribute-fields-type-deep.c:36:3-36:20) + > write with [mhp:{tid=[main]; created={[main, t_fun@92-distribute-fields-type-deep.c:42:3-42:40#⊤]}}, threadflag:(MT mode:Multithreaded (main), bool:true), thread:[main]] (conf. 100) (exp: & tmp->t) (92-distribute-fields-type-deep.c:44:3-44:17) 12c12 - < write with thread:[main, t_fun@92-distribute-fields-type-deep.c:42:3-42:40] (conf. 100) (exp: & tmp->field) (92-distribute-fields-type-deep.c:36:3-36:20) + < write with [threadflag:(MT mode:Multithreaded (other), bool:true), thread:[main, t_fun@92-distribute-fields-type-deep.c:42:3-42:40]] (conf. 100) (exp: & tmp->field) (92-distribute-fields-type-deep.c:36:3-36:20) --- - > write with [mhp:{tid=[main, t_fun@92-distribute-fields-type-deep.c:42:3-42:40#⊤]}, thread:[main, t_fun@92-distribute-fields-type-deep.c:42:3-42:40#⊤]] (conf. 100) (exp: & tmp->field) (92-distribute-fields-type-deep.c:36:3-36:20) + > write with [mhp:{tid=[main, t_fun@92-distribute-fields-type-deep.c:42:3-42:40#⊤]}, threadflag:(MT mode:Multithreaded (other), bool:true), thread:[main, t_fun@92-distribute-fields-type-deep.c:42:3-42:40#⊤]] (conf. 100) (exp: & tmp->field) (92-distribute-fields-type-deep.c:36:3-36:20) 14c14 - < write with [mhp:{created={[main, t_fun@92-distribute-fields-type-deep.c:42:3-42:40]}}, thread:[main]] (conf. 100) (exp: & tmp->t) (92-distribute-fields-type-deep.c:44:3-44:17) + < write with [mhp:{created={[main, t_fun@92-distribute-fields-type-deep.c:42:3-42:40]}}, threadflag:(MT mode:Multithreaded (main), bool:true), thread:[main]] (conf. 100) (exp: & tmp->t) (92-distribute-fields-type-deep.c:44:3-44:17) --- - > write with [mhp:{tid=[main]; created={[main, t_fun@92-distribute-fields-type-deep.c:42:3-42:40#⊤]}}, thread:[main]] (conf. 100) (exp: & tmp->t) (92-distribute-fields-type-deep.c:44:3-44:17) + > write with [mhp:{tid=[main]; created={[main, t_fun@92-distribute-fields-type-deep.c:42:3-42:40#⊤]}}, threadflag:(MT mode:Multithreaded (main), bool:true), thread:[main]] (conf. 100) (exp: & tmp->t) (92-distribute-fields-type-deep.c:44:3-44:17) [1] diff --git a/tests/regression/04-mutex/93-distribute-fields-type-global.t b/tests/regression/04-mutex/93-distribute-fields-type-global.t index 7e0dc61a3c..c5ca112278 100644 --- a/tests/regression/04-mutex/93-distribute-fields-type-global.t +++ b/tests/regression/04-mutex/93-distribute-fields-type-global.t @@ -1,17 +1,17 @@ $ goblint --enable warn.deterministic --enable allglobs 93-distribute-fields-type-global.c 2>&1 | tee default-output.txt [Warning][Behavior > Undefined > NullPointerDereference][CWE-476] May dereference NULL pointer (93-distribute-fields-type-global.c:13:3-13:29) [Warning][Race] Memory location s.field (race with conf. 110): (93-distribute-fields-type-global.c:8:10-8:11) - read with thread:[main, t_fun@93-distribute-fields-type-global.c:20:3-20:40] (conf. 100) (exp: & tmp->field) (93-distribute-fields-type-global.c:13:3-13:29) - write with [mhp:{created={[main, t_fun@93-distribute-fields-type-global.c:20:3-20:40]}}, thread:[main]] (conf. 110) (exp: & s) (93-distribute-fields-type-global.c:22:3-22:9) + read with [threadflag:(MT mode:Multithreaded (other), bool:true), thread:[main, t_fun@93-distribute-fields-type-global.c:20:3-20:40]] (conf. 100) (exp: & tmp->field) (93-distribute-fields-type-global.c:13:3-13:29) + write with [mhp:{created={[main, t_fun@93-distribute-fields-type-global.c:20:3-20:40]}}, threadflag:(MT mode:Multithreaded (main), bool:true), thread:[main]] (conf. 110) (exp: & s) (93-distribute-fields-type-global.c:22:3-22:9) [Info][Race] Memory locations race summary: safe: 2 vulnerable: 0 unsafe: 1 total memory locations: 3 [Success][Race] Memory location (struct S).field (safe): - read with thread:[main, t_fun@93-distribute-fields-type-global.c:20:3-20:40] (conf. 100) (exp: & tmp->field) (93-distribute-fields-type-global.c:13:3-13:29) + read with [threadflag:(MT mode:Multithreaded (other), bool:true), thread:[main, t_fun@93-distribute-fields-type-global.c:20:3-20:40]] (conf. 100) (exp: & tmp->field) (93-distribute-fields-type-global.c:13:3-13:29) [Success][Race] Memory location s (safe): (93-distribute-fields-type-global.c:8:10-8:11) - write with [mhp:{created={[main, t_fun@93-distribute-fields-type-global.c:20:3-20:40]}}, thread:[main]] (conf. 110) (exp: & s) (93-distribute-fields-type-global.c:22:3-22:9) + write with [mhp:{created={[main, t_fun@93-distribute-fields-type-global.c:20:3-20:40]}}, threadflag:(MT mode:Multithreaded (main), bool:true), thread:[main]] (conf. 110) (exp: & s) (93-distribute-fields-type-global.c:22:3-22:9) [Info][Deadcode] Logical lines of code (LLoC) summary: live: 7 dead: 0 @@ -27,17 +27,17 @@ $ diff default-output.txt full-output.txt 3,4c3,4 - < read with thread:[main, t_fun@93-distribute-fields-type-global.c:20:3-20:40] (conf. 100) (exp: & tmp->field) (93-distribute-fields-type-global.c:13:3-13:29) - < write with [mhp:{created={[main, t_fun@93-distribute-fields-type-global.c:20:3-20:40]}}, thread:[main]] (conf. 110) (exp: & s) (93-distribute-fields-type-global.c:22:3-22:9) + < read with [threadflag:(MT mode:Multithreaded (other), bool:true), thread:[main, t_fun@93-distribute-fields-type-global.c:20:3-20:40]] (conf. 100) (exp: & tmp->field) (93-distribute-fields-type-global.c:13:3-13:29) + < write with [mhp:{created={[main, t_fun@93-distribute-fields-type-global.c:20:3-20:40]}}, threadflag:(MT mode:Multithreaded (main), bool:true), thread:[main]] (conf. 110) (exp: & s) (93-distribute-fields-type-global.c:22:3-22:9) --- - > read with [mhp:{tid=[main, t_fun@93-distribute-fields-type-global.c:20:3-20:40#⊤]}, thread:[main, t_fun@93-distribute-fields-type-global.c:20:3-20:40#⊤]] (conf. 100) (exp: & tmp->field) (93-distribute-fields-type-global.c:13:3-13:29) - > write with [mhp:{tid=[main]; created={[main, t_fun@93-distribute-fields-type-global.c:20:3-20:40#⊤]}}, thread:[main]] (conf. 110) (exp: & s) (93-distribute-fields-type-global.c:22:3-22:9) + > read with [mhp:{tid=[main, t_fun@93-distribute-fields-type-global.c:20:3-20:40#⊤]}, threadflag:(MT mode:Multithreaded (other), bool:true), thread:[main, t_fun@93-distribute-fields-type-global.c:20:3-20:40#⊤]] (conf. 100) (exp: & tmp->field) (93-distribute-fields-type-global.c:13:3-13:29) + > write with [mhp:{tid=[main]; created={[main, t_fun@93-distribute-fields-type-global.c:20:3-20:40#⊤]}}, threadflag:(MT mode:Multithreaded (main), bool:true), thread:[main]] (conf. 110) (exp: & s) (93-distribute-fields-type-global.c:22:3-22:9) 11c11 - < read with thread:[main, t_fun@93-distribute-fields-type-global.c:20:3-20:40] (conf. 100) (exp: & tmp->field) (93-distribute-fields-type-global.c:13:3-13:29) + < read with [threadflag:(MT mode:Multithreaded (other), bool:true), thread:[main, t_fun@93-distribute-fields-type-global.c:20:3-20:40]] (conf. 100) (exp: & tmp->field) (93-distribute-fields-type-global.c:13:3-13:29) --- - > read with [mhp:{tid=[main, t_fun@93-distribute-fields-type-global.c:20:3-20:40#⊤]}, thread:[main, t_fun@93-distribute-fields-type-global.c:20:3-20:40#⊤]] (conf. 100) (exp: & tmp->field) (93-distribute-fields-type-global.c:13:3-13:29) + > read with [mhp:{tid=[main, t_fun@93-distribute-fields-type-global.c:20:3-20:40#⊤]}, threadflag:(MT mode:Multithreaded (other), bool:true), thread:[main, t_fun@93-distribute-fields-type-global.c:20:3-20:40#⊤]] (conf. 100) (exp: & tmp->field) (93-distribute-fields-type-global.c:13:3-13:29) 13c13 - < write with [mhp:{created={[main, t_fun@93-distribute-fields-type-global.c:20:3-20:40]}}, thread:[main]] (conf. 110) (exp: & s) (93-distribute-fields-type-global.c:22:3-22:9) + < write with [mhp:{created={[main, t_fun@93-distribute-fields-type-global.c:20:3-20:40]}}, threadflag:(MT mode:Multithreaded (main), bool:true), thread:[main]] (conf. 110) (exp: & s) (93-distribute-fields-type-global.c:22:3-22:9) --- - > write with [mhp:{tid=[main]; created={[main, t_fun@93-distribute-fields-type-global.c:20:3-20:40#⊤]}}, thread:[main]] (conf. 110) (exp: & s) (93-distribute-fields-type-global.c:22:3-22:9) + > write with [mhp:{tid=[main]; created={[main, t_fun@93-distribute-fields-type-global.c:20:3-20:40#⊤]}}, threadflag:(MT mode:Multithreaded (main), bool:true), thread:[main]] (conf. 110) (exp: & s) (93-distribute-fields-type-global.c:22:3-22:9) [1] diff --git a/tests/regression/06-symbeq/14-list_entry_rc.t b/tests/regression/06-symbeq/14-list_entry_rc.t index 0e5ec3ce9f..a94e910a9d 100644 --- a/tests/regression/06-symbeq/14-list_entry_rc.t +++ b/tests/regression/06-symbeq/14-list_entry_rc.t @@ -6,15 +6,15 @@ dead: 0 total lines: 23 [Warning][Race] Memory location (alloc@sid:$SID@tid:[main])[?].datum (race with conf. 110): (14-list_entry_rc.c:41:3-41:35) - write with thread:[main, t_fun@14-list_entry_rc.c:45:3-45:40] (conf. 110) (exp: & s->datum) (14-list_entry_rc.c:27:3-27:13) - write with [mhp:{created={[main, t_fun@14-list_entry_rc.c:45:3-45:40]}}, thread:[main]] (conf. 110) (exp: & s->datum) (14-list_entry_rc.c:27:3-27:13) - read with thread:[main, t_fun@14-list_entry_rc.c:45:3-45:40] (conf. 110) (exp: & s->datum) (14-list_entry_rc.c:27:3-27:13) - read with [mhp:{created={[main, t_fun@14-list_entry_rc.c:45:3-45:40]}}, thread:[main]] (conf. 110) (exp: & s->datum) (14-list_entry_rc.c:27:3-27:13) + write with [threadflag:(MT mode:Multithreaded (other), bool:true), thread:[main, t_fun@14-list_entry_rc.c:45:3-45:40]] (conf. 110) (exp: & s->datum) (14-list_entry_rc.c:27:3-27:13) + write with [mhp:{created={[main, t_fun@14-list_entry_rc.c:45:3-45:40]}}, threadflag:(MT mode:Multithreaded (main), bool:true), thread:[main]] (conf. 110) (exp: & s->datum) (14-list_entry_rc.c:27:3-27:13) + read with [threadflag:(MT mode:Multithreaded (other), bool:true), thread:[main, t_fun@14-list_entry_rc.c:45:3-45:40]] (conf. 110) (exp: & s->datum) (14-list_entry_rc.c:27:3-27:13) + read with [mhp:{created={[main, t_fun@14-list_entry_rc.c:45:3-45:40]}}, threadflag:(MT mode:Multithreaded (main), bool:true), thread:[main]] (conf. 110) (exp: & s->datum) (14-list_entry_rc.c:27:3-27:13) [Info][Race] Memory locations race summary: - safe: 1 + safe: 2 vulnerable: 0 unsafe: 1 - total memory locations: 2 + total memory locations: 3 $ goblint --enable ana.race.direct-arithmetic --set ana.activated[+] "'var_eq'" --set ana.activated[+] "'symb_locks'" --enable dbg.full-output 14-list_entry_rc.c 2>&1 | sed -r 's/sid:[0-9]+/sid:$SID/' > full-output.txt @@ -25,14 +25,14 @@ > [Warning][Unknown] unlocking mutex ((alloc@sid:$SID@tid:[main](#top))[def_exc:1].mutex) which may not be held (14-list_entry_rc.c:28:3-28:34) 7,11c7,11 < [Warning][Race] Memory location (alloc@sid:$SID@tid:[main])[?].datum (race with conf. 110): (14-list_entry_rc.c:41:3-41:35) - < write with thread:[main, t_fun@14-list_entry_rc.c:45:3-45:40] (conf. 110) (exp: & s->datum) (14-list_entry_rc.c:27:3-27:13) - < write with [mhp:{created={[main, t_fun@14-list_entry_rc.c:45:3-45:40]}}, thread:[main]] (conf. 110) (exp: & s->datum) (14-list_entry_rc.c:27:3-27:13) - < read with thread:[main, t_fun@14-list_entry_rc.c:45:3-45:40] (conf. 110) (exp: & s->datum) (14-list_entry_rc.c:27:3-27:13) - < read with [mhp:{created={[main, t_fun@14-list_entry_rc.c:45:3-45:40]}}, thread:[main]] (conf. 110) (exp: & s->datum) (14-list_entry_rc.c:27:3-27:13) + < write with [threadflag:(MT mode:Multithreaded (other), bool:true), thread:[main, t_fun@14-list_entry_rc.c:45:3-45:40]] (conf. 110) (exp: & s->datum) (14-list_entry_rc.c:27:3-27:13) + < write with [mhp:{created={[main, t_fun@14-list_entry_rc.c:45:3-45:40]}}, threadflag:(MT mode:Multithreaded (main), bool:true), thread:[main]] (conf. 110) (exp: & s->datum) (14-list_entry_rc.c:27:3-27:13) + < read with [threadflag:(MT mode:Multithreaded (other), bool:true), thread:[main, t_fun@14-list_entry_rc.c:45:3-45:40]] (conf. 110) (exp: & s->datum) (14-list_entry_rc.c:27:3-27:13) + < read with [mhp:{created={[main, t_fun@14-list_entry_rc.c:45:3-45:40]}}, threadflag:(MT mode:Multithreaded (main), bool:true), thread:[main]] (conf. 110) (exp: & s->datum) (14-list_entry_rc.c:27:3-27:13) --- > [Warning][Race] Memory location (alloc@sid:$SID@tid:[main](#top))[?].datum (race with conf. 110): (14-list_entry_rc.c:41:3-41:35) - > write with [mhp:{tid=[main, t_fun@14-list_entry_rc.c:45:3-45:40#⊤]}, thread:[main, t_fun@14-list_entry_rc.c:45:3-45:40#⊤]] (conf. 110) (exp: & s->datum) (14-list_entry_rc.c:27:3-27:13) - > write with [mhp:{tid=[main]; created={[main, t_fun@14-list_entry_rc.c:45:3-45:40#⊤]}}, thread:[main]] (conf. 110) (exp: & s->datum) (14-list_entry_rc.c:27:3-27:13) - > read with [mhp:{tid=[main, t_fun@14-list_entry_rc.c:45:3-45:40#⊤]}, thread:[main, t_fun@14-list_entry_rc.c:45:3-45:40#⊤]] (conf. 110) (exp: & s->datum) (14-list_entry_rc.c:27:3-27:13) - > read with [mhp:{tid=[main]; created={[main, t_fun@14-list_entry_rc.c:45:3-45:40#⊤]}}, thread:[main]] (conf. 110) (exp: & s->datum) (14-list_entry_rc.c:27:3-27:13) + > write with [mhp:{tid=[main, t_fun@14-list_entry_rc.c:45:3-45:40#⊤]}, threadflag:(MT mode:Multithreaded (other), bool:true), thread:[main, t_fun@14-list_entry_rc.c:45:3-45:40#⊤]] (conf. 110) (exp: & s->datum) (14-list_entry_rc.c:27:3-27:13) + > write with [mhp:{tid=[main]; created={[main, t_fun@14-list_entry_rc.c:45:3-45:40#⊤]}}, threadflag:(MT mode:Multithreaded (main), bool:true), thread:[main]] (conf. 110) (exp: & s->datum) (14-list_entry_rc.c:27:3-27:13) + > read with [mhp:{tid=[main, t_fun@14-list_entry_rc.c:45:3-45:40#⊤]}, threadflag:(MT mode:Multithreaded (other), bool:true), thread:[main, t_fun@14-list_entry_rc.c:45:3-45:40#⊤]] (conf. 110) (exp: & s->datum) (14-list_entry_rc.c:27:3-27:13) + > read with [mhp:{tid=[main]; created={[main, t_fun@14-list_entry_rc.c:45:3-45:40#⊤]}}, threadflag:(MT mode:Multithreaded (main), bool:true), thread:[main]] (conf. 110) (exp: & s->datum) (14-list_entry_rc.c:27:3-27:13) [1] diff --git a/tests/regression/06-symbeq/16-type_rc.t b/tests/regression/06-symbeq/16-type_rc.t index a5f977008d..703b73e0d0 100644 --- a/tests/regression/06-symbeq/16-type_rc.t +++ b/tests/regression/06-symbeq/16-type_rc.t @@ -6,8 +6,8 @@ Disable info messages because race summary contains (safe) memory location count [Warning][Behavior > Undefined > NullPointerDereference][CWE-476] May dereference NULL pointer (16-type_rc.c:33:3-33:16) [Warning][Behavior > Undefined > NullPointerDereference][CWE-476] May dereference NULL pointer (16-type_rc.c:36:3-36:9) [Warning][Race] Memory location (struct s).datum (race with conf. 100): - write with thread:[main, t_fun@16-type_rc.c:35:3-35:37] (conf. 100) (exp: & s->datum) (16-type_rc.c:21:3-21:15) - write with [mhp:{created={[main, t_fun@16-type_rc.c:35:3-35:37]}}, thread:[main]] (conf. 100) (exp: & *d) (16-type_rc.c:36:3-36:9) + write with [threadflag:(MT mode:Multithreaded (other), bool:true), thread:[main, t_fun@16-type_rc.c:35:3-35:37]] (conf. 100) (exp: & s->datum) (16-type_rc.c:21:3-21:15) + write with [mhp:{created={[main, t_fun@16-type_rc.c:35:3-35:37]}}, threadflag:(MT mode:Multithreaded (main), bool:true), thread:[main]] (conf. 100) (exp: & *d) (16-type_rc.c:36:3-36:9) [Error][Imprecise][Unsound] Function definition missing for get_s (16-type_rc.c:20:12-20:24) [Error][Imprecise][Unsound] Function definition missing for get_s (16-type_rc.c:31:3-31:14) [Error][Imprecise][Unsound] Function definition missing @@ -18,7 +18,7 @@ Disable info messages because race summary contains (safe) memory location count [Warning][Behavior > Undefined > NullPointerDereference][CWE-476] May dereference NULL pointer (16-type_rc.c:33:3-33:16) [Warning][Behavior > Undefined > NullPointerDereference][CWE-476] May dereference NULL pointer (16-type_rc.c:36:3-36:9) [Success][Race] Memory location (struct s).datum (safe): - write with thread:[main, t_fun@16-type_rc.c:35:3-35:37] (conf. 100) (exp: & s->datum) (16-type_rc.c:21:3-21:15) + write with [threadflag:(MT mode:Multithreaded (other), bool:true), thread:[main, t_fun@16-type_rc.c:35:3-35:37]] (conf. 100) (exp: & s->datum) (16-type_rc.c:21:3-21:15) [Error][Imprecise][Unsound] Function definition missing for get_s (16-type_rc.c:20:12-20:24) [Error][Imprecise][Unsound] Function definition missing for get_s (16-type_rc.c:31:3-31:14) [Error][Imprecise][Unsound] Function definition missing @@ -27,18 +27,18 @@ Disable info messages because race summary contains (safe) memory location count $ diff default-output-1.txt full-output-1.txt 6,7c6,7 - < write with thread:[main, t_fun@16-type_rc.c:35:3-35:37] (conf. 100) (exp: & s->datum) (16-type_rc.c:21:3-21:15) - < write with [mhp:{created={[main, t_fun@16-type_rc.c:35:3-35:37]}}, thread:[main]] (conf. 100) (exp: & *d) (16-type_rc.c:36:3-36:9) + < write with [threadflag:(MT mode:Multithreaded (other), bool:true), thread:[main, t_fun@16-type_rc.c:35:3-35:37]] (conf. 100) (exp: & s->datum) (16-type_rc.c:21:3-21:15) + < write with [mhp:{created={[main, t_fun@16-type_rc.c:35:3-35:37]}}, threadflag:(MT mode:Multithreaded (main), bool:true), thread:[main]] (conf. 100) (exp: & *d) (16-type_rc.c:36:3-36:9) --- - > write with [mhp:{tid=[main, t_fun@16-type_rc.c:35:3-35:37#⊤]}, thread:[main, t_fun@16-type_rc.c:35:3-35:37#⊤]] (conf. 100) (exp: & s->datum) (16-type_rc.c:21:3-21:15) - > write with [mhp:{tid=[main]; created={[main, t_fun@16-type_rc.c:35:3-35:37#⊤]}}, thread:[main]] (conf. 100) (exp: & *d) (16-type_rc.c:36:3-36:9) + > write with [mhp:{tid=[main, t_fun@16-type_rc.c:35:3-35:37#⊤]}, threadflag:(MT mode:Multithreaded (other), bool:true), thread:[main, t_fun@16-type_rc.c:35:3-35:37#⊤]] (conf. 100) (exp: & s->datum) (16-type_rc.c:21:3-21:15) + > write with [mhp:{tid=[main]; created={[main, t_fun@16-type_rc.c:35:3-35:37#⊤]}}, threadflag:(MT mode:Multithreaded (main), bool:true), thread:[main]] (conf. 100) (exp: & *d) (16-type_rc.c:36:3-36:9) [1] $ goblint --enable warn.deterministic --disable warn.info --disable ana.race.direct-arithmetic --set ana.activated[+] "'var_eq'" --set ana.activated[+] "'symb_locks'" --enable allglobs --enable dbg.full-output 16-type_rc.c > full-output-2.txt 2>&1 $ diff default-output-2.txt full-output-2.txt 6c6 - < write with thread:[main, t_fun@16-type_rc.c:35:3-35:37] (conf. 100) (exp: & s->datum) (16-type_rc.c:21:3-21:15) + < write with [threadflag:(MT mode:Multithreaded (other), bool:true), thread:[main, t_fun@16-type_rc.c:35:3-35:37]] (conf. 100) (exp: & s->datum) (16-type_rc.c:21:3-21:15) --- - > write with [mhp:{tid=[main, t_fun@16-type_rc.c:35:3-35:37#⊤]}, thread:[main, t_fun@16-type_rc.c:35:3-35:37#⊤]] (conf. 100) (exp: & s->datum) (16-type_rc.c:21:3-21:15) + > write with [mhp:{tid=[main, t_fun@16-type_rc.c:35:3-35:37#⊤]}, threadflag:(MT mode:Multithreaded (other), bool:true), thread:[main, t_fun@16-type_rc.c:35:3-35:37#⊤]] (conf. 100) (exp: & s->datum) (16-type_rc.c:21:3-21:15) [1] diff --git a/tests/regression/06-symbeq/21-mult_accs_rc.t b/tests/regression/06-symbeq/21-mult_accs_rc.t index 2eacd0382e..3b1c54990e 100644 --- a/tests/regression/06-symbeq/21-mult_accs_rc.t +++ b/tests/regression/06-symbeq/21-mult_accs_rc.t @@ -8,8 +8,8 @@ Disable info messages because race summary contains (safe) memory location count [Warning][Behavior > Undefined > NullPointerDereference][CWE-476] May dereference NULL pointer (21-mult_accs_rc.c:29:3-29:15) [Warning][Behavior > Undefined > NullPointerDereference][CWE-476] May dereference NULL pointer (21-mult_accs_rc.c:34:3-34:9) [Warning][Race] Memory location (struct s).data (race with conf. 100): - write with thread:[main, t_fun@21-mult_accs_rc.c:31:3-31:37] (conf. 100) (exp: & s->data) (21-mult_accs_rc.c:16:3-16:14) - write with [symblock:{p-lock:*.mutex}, mhp:{created={[main, t_fun@21-mult_accs_rc.c:31:3-31:37]}}, thread:[main]] (conf. 100) (exp: & *d) (21-mult_accs_rc.c:34:3-34:9) + write with [threadflag:(MT mode:Multithreaded (other), bool:true), thread:[main, t_fun@21-mult_accs_rc.c:31:3-31:37]] (conf. 100) (exp: & s->data) (21-mult_accs_rc.c:16:3-16:14) + write with [symblock:{p-lock:*.mutex}, mhp:{created={[main, t_fun@21-mult_accs_rc.c:31:3-31:37]}}, threadflag:(MT mode:Multithreaded (main), bool:true), thread:[main]] (conf. 100) (exp: & *d) (21-mult_accs_rc.c:34:3-34:9) [Warning][Unknown] locking NULL mutex (21-mult_accs_rc.c:14:3-14:32) [Warning][Unknown] unlocking NULL mutex (21-mult_accs_rc.c:17:3-17:34) [Warning][Unknown] unlocking unknown mutex which may not be held (21-mult_accs_rc.c:17:3-17:34) @@ -29,7 +29,7 @@ Disable info messages because race summary contains (safe) memory location count [Warning][Behavior > Undefined > NullPointerDereference][CWE-476] May dereference NULL pointer (21-mult_accs_rc.c:29:3-29:15) [Warning][Behavior > Undefined > NullPointerDereference][CWE-476] May dereference NULL pointer (21-mult_accs_rc.c:34:3-34:9) [Success][Race] Memory location (struct s).data (safe): - write with thread:[main, t_fun@21-mult_accs_rc.c:31:3-31:37] (conf. 100) (exp: & s->data) (21-mult_accs_rc.c:16:3-16:14) + write with [threadflag:(MT mode:Multithreaded (other), bool:true), thread:[main, t_fun@21-mult_accs_rc.c:31:3-31:37]] (conf. 100) (exp: & s->data) (21-mult_accs_rc.c:16:3-16:14) [Warning][Unknown] locking NULL mutex (21-mult_accs_rc.c:14:3-14:32) [Warning][Unknown] unlocking NULL mutex (21-mult_accs_rc.c:17:3-17:34) [Warning][Unknown] unlocking unknown mutex which may not be held (21-mult_accs_rc.c:17:3-17:34) @@ -45,18 +45,18 @@ Disable info messages because race summary contains (safe) memory location count $ diff default-output-1.txt full-output-1.txt 8,9c8,9 - < write with thread:[main, t_fun@21-mult_accs_rc.c:31:3-31:37] (conf. 100) (exp: & s->data) (21-mult_accs_rc.c:16:3-16:14) - < write with [symblock:{p-lock:*.mutex}, mhp:{created={[main, t_fun@21-mult_accs_rc.c:31:3-31:37]}}, thread:[main]] (conf. 100) (exp: & *d) (21-mult_accs_rc.c:34:3-34:9) + < write with [threadflag:(MT mode:Multithreaded (other), bool:true), thread:[main, t_fun@21-mult_accs_rc.c:31:3-31:37]] (conf. 100) (exp: & s->data) (21-mult_accs_rc.c:16:3-16:14) + < write with [symblock:{p-lock:*.mutex}, mhp:{created={[main, t_fun@21-mult_accs_rc.c:31:3-31:37]}}, threadflag:(MT mode:Multithreaded (main), bool:true), thread:[main]] (conf. 100) (exp: & *d) (21-mult_accs_rc.c:34:3-34:9) --- - > write with [mhp:{tid=[main, t_fun@21-mult_accs_rc.c:31:3-31:37#⊤]}, thread:[main, t_fun@21-mult_accs_rc.c:31:3-31:37#⊤]] (conf. 100) (exp: & s->data) (21-mult_accs_rc.c:16:3-16:14) - > write with [symblock:{p-lock:*.mutex}, mhp:{tid=[main]; created={[main, t_fun@21-mult_accs_rc.c:31:3-31:37#⊤]}}, thread:[main]] (conf. 100) (exp: & *d) (21-mult_accs_rc.c:34:3-34:9) + > write with [mhp:{tid=[main, t_fun@21-mult_accs_rc.c:31:3-31:37#⊤]}, threadflag:(MT mode:Multithreaded (other), bool:true), thread:[main, t_fun@21-mult_accs_rc.c:31:3-31:37#⊤]] (conf. 100) (exp: & s->data) (21-mult_accs_rc.c:16:3-16:14) + > write with [symblock:{p-lock:*.mutex}, mhp:{tid=[main]; created={[main, t_fun@21-mult_accs_rc.c:31:3-31:37#⊤]}}, threadflag:(MT mode:Multithreaded (main), bool:true), thread:[main]] (conf. 100) (exp: & *d) (21-mult_accs_rc.c:34:3-34:9) [1] $ goblint --enable warn.deterministic --disable warn.info --disable ana.race.direct-arithmetic --set ana.activated[+] "'var_eq'" --set ana.activated[+] "'symb_locks'" --enable allglobs --enable dbg.full-output 21-mult_accs_rc.c > full-output-2.txt 2>&1 $ diff default-output-2.txt full-output-2.txt 8c8 - < write with thread:[main, t_fun@21-mult_accs_rc.c:31:3-31:37] (conf. 100) (exp: & s->data) (21-mult_accs_rc.c:16:3-16:14) + < write with [threadflag:(MT mode:Multithreaded (other), bool:true), thread:[main, t_fun@21-mult_accs_rc.c:31:3-31:37]] (conf. 100) (exp: & s->data) (21-mult_accs_rc.c:16:3-16:14) --- - > write with [mhp:{tid=[main, t_fun@21-mult_accs_rc.c:31:3-31:37#⊤]}, thread:[main, t_fun@21-mult_accs_rc.c:31:3-31:37#⊤]] (conf. 100) (exp: & s->data) (21-mult_accs_rc.c:16:3-16:14) + > write with [mhp:{tid=[main, t_fun@21-mult_accs_rc.c:31:3-31:37#⊤]}, threadflag:(MT mode:Multithreaded (other), bool:true), thread:[main, t_fun@21-mult_accs_rc.c:31:3-31:37#⊤]] (conf. 100) (exp: & s->data) (21-mult_accs_rc.c:16:3-16:14) [1] diff --git a/tests/regression/13-privatized/63-access-threadspawn-lval.t b/tests/regression/13-privatized/63-access-threadspawn-lval.t index 313459637c..d0d7f90bee 100644 --- a/tests/regression/13-privatized/63-access-threadspawn-lval.t +++ b/tests/regression/13-privatized/63-access-threadspawn-lval.t @@ -12,10 +12,11 @@ Should have (safe) write accesses to id1 and id2: dead: 0 total lines: 13 [Success][Race] Memory location id1 (safe): (63-access-threadspawn-lval.c:4:11-4:14) - write with [multi:false, thread:[main]] (conf. 110) (exp: & *((pthread_t * __restrict )(& id1))) (63-access-threadspawn-lval.c:27:3-27:37) + write with [threadflag:(MT mode:Singlethreaded, bool:false), thread:[main]] (conf. 110) (exp: (pthread_t * __restrict )(& id1)) (63-access-threadspawn-lval.c:27:3-27:37) + write with [threadflag:(MT mode:Singlethreaded, bool:false), thread:[main]] (conf. 110) (exp: & *((pthread_t * __restrict )(& id1))) (63-access-threadspawn-lval.c:27:3-27:37) [Success][Race] Memory location id2 (safe): (63-access-threadspawn-lval.c:5:11-5:14) - write with [mhp:{created={[main, f@63-access-threadspawn-lval.c:27:3-27:37]}}, thread:[main]] (conf. 110) (exp: (pthread_t * __restrict )(& id2)) (63-access-threadspawn-lval.c:28:3-28:37) - write with [mhp:{created={[main, f@63-access-threadspawn-lval.c:27:3-27:37]}}, thread:[main]] (conf. 110) (exp: & *((pthread_t * __restrict )(& id2))) (63-access-threadspawn-lval.c:28:3-28:37) + write with [mhp:{created={[main, f@63-access-threadspawn-lval.c:27:3-27:37]}}, threadflag:(MT mode:Multithreaded (main), bool:true), thread:[main]] (conf. 110) (exp: (pthread_t * __restrict )(& id2)) (63-access-threadspawn-lval.c:28:3-28:37) + write with [mhp:{created={[main, f@63-access-threadspawn-lval.c:27:3-27:37]}}, threadflag:(MT mode:Multithreaded (main), bool:true), thread:[main]] (conf. 110) (exp: & *((pthread_t * __restrict )(& id2))) (63-access-threadspawn-lval.c:28:3-28:37) [Info][Race] Memory locations race summary: safe: 2 vulnerable: 0 diff --git a/tests/regression/13-privatized/64-access-invalidate.t b/tests/regression/13-privatized/64-access-invalidate.t index 28227ec475..165fbe9aea 100644 --- a/tests/regression/13-privatized/64-access-invalidate.t +++ b/tests/regression/13-privatized/64-access-invalidate.t @@ -12,7 +12,8 @@ Should have (safe) write access to id1 and magic2 invalidate to A: dead: 0 total lines: 10 [Success][Race] Memory location id (safe): (64-access-invalidate.c:4:11-4:13) - write with [multi:false, thread:[main]] (conf. 110) (exp: & *((pthread_t * __restrict )(& id))) (64-access-invalidate.c:21:3-21:36) + write with [threadflag:(MT mode:Singlethreaded, bool:false), thread:[main]] (conf. 110) (exp: (pthread_t * __restrict )(& id)) (64-access-invalidate.c:21:3-21:36) + write with [threadflag:(MT mode:Singlethreaded, bool:false), thread:[main]] (conf. 110) (exp: & *((pthread_t * __restrict )(& id))) (64-access-invalidate.c:21:3-21:36) [Info][Race] Memory locations race summary: safe: 1 vulnerable: 0 diff --git a/tests/regression/29-svcomp/16-atomic_priv.t b/tests/regression/29-svcomp/16-atomic_priv.t index 1662f881b7..04fb1994a6 100644 --- a/tests/regression/29-svcomp/16-atomic_priv.t +++ b/tests/regression/29-svcomp/16-atomic_priv.t @@ -9,9 +9,9 @@ dead: 0 total lines: 17 [Warning][Race] Memory location myglobal (race with conf. 110): (16-atomic_priv.c:8:5-8:17) - write with [lock:{[__VERIFIER_atomic]}, thread:[main, t_fun@16-atomic_priv.c:23:3-23:40]] (conf. 110) (exp: & myglobal) (16-atomic_priv.c:13:3-13:13) - write with [lock:{[__VERIFIER_atomic]}, thread:[main, t_fun@16-atomic_priv.c:23:3-23:40]] (conf. 110) (exp: & myglobal) (16-atomic_priv.c:15:3-15:13) - read with [mhp:{created={[main, t_fun@16-atomic_priv.c:23:3-23:40]}}, thread:[main]] (conf. 110) (exp: & myglobal) (16-atomic_priv.c:24:3-24:33) + write with [lock:{[__VERIFIER_atomic]}, threadflag:(MT mode:Multithreaded (other), bool:true), thread:[main, t_fun@16-atomic_priv.c:23:3-23:40]] (conf. 110) (exp: & myglobal) (16-atomic_priv.c:13:3-13:13) + write with [lock:{[__VERIFIER_atomic]}, threadflag:(MT mode:Multithreaded (other), bool:true), thread:[main, t_fun@16-atomic_priv.c:23:3-23:40]] (conf. 110) (exp: & myglobal) (16-atomic_priv.c:15:3-15:13) + read with [mhp:{created={[main, t_fun@16-atomic_priv.c:23:3-23:40]}}, threadflag:(MT mode:Multithreaded (main), bool:true), thread:[main]] (conf. 110) (exp: & myglobal) (16-atomic_priv.c:24:3-24:33) [Info][Witness] witness generation summary: location invariants: 0 loop invariants: 0 @@ -63,9 +63,9 @@ Non-atomic privatization: dead: 0 total lines: 17 [Warning][Race] Memory location myglobal (race with conf. 110): (16-atomic_priv.c:8:5-8:17) - write with [lock:{[__VERIFIER_atomic]}, thread:[main, t_fun@16-atomic_priv.c:23:3-23:40]] (conf. 110) (exp: & myglobal) (16-atomic_priv.c:13:3-13:13) - write with [lock:{[__VERIFIER_atomic]}, thread:[main, t_fun@16-atomic_priv.c:23:3-23:40]] (conf. 110) (exp: & myglobal) (16-atomic_priv.c:15:3-15:13) - read with [mhp:{created={[main, t_fun@16-atomic_priv.c:23:3-23:40]}}, thread:[main]] (conf. 110) (exp: & myglobal) (16-atomic_priv.c:24:3-24:33) + write with [lock:{[__VERIFIER_atomic]}, threadflag:(MT mode:Multithreaded (other), bool:true), thread:[main, t_fun@16-atomic_priv.c:23:3-23:40]] (conf. 110) (exp: & myglobal) (16-atomic_priv.c:13:3-13:13) + write with [lock:{[__VERIFIER_atomic]}, threadflag:(MT mode:Multithreaded (other), bool:true), thread:[main, t_fun@16-atomic_priv.c:23:3-23:40]] (conf. 110) (exp: & myglobal) (16-atomic_priv.c:15:3-15:13) + read with [mhp:{created={[main, t_fun@16-atomic_priv.c:23:3-23:40]}}, threadflag:(MT mode:Multithreaded (main), bool:true), thread:[main]] (conf. 110) (exp: & myglobal) (16-atomic_priv.c:24:3-24:33) [Info][Witness] witness generation summary: location invariants: 0 loop invariants: 0 diff --git a/tests/regression/36-apron/12-traces-min-rpb1.t b/tests/regression/36-apron/12-traces-min-rpb1.t index 2a760c0dcb..d6ce4301ee 100644 --- a/tests/regression/36-apron/12-traces-min-rpb1.t +++ b/tests/regression/36-apron/12-traces-min-rpb1.t @@ -7,11 +7,11 @@ dead: 0 total lines: 18 [Warning][Race] Memory location h (race with conf. 110): (12-traces-min-rpb1.c:8:5-8:10) - write with [lock:{A}, thread:[main, t_fun@12-traces-min-rpb1.c:25:3-25:40]] (conf. 110) (exp: & h) (12-traces-min-rpb1.c:15:3-15:8) - read with [mhp:{created={[main, t_fun@12-traces-min-rpb1.c:25:3-25:40]}}, thread:[main]] (conf. 110) (exp: & h) (12-traces-min-rpb1.c:27:3-27:26) + write with [lock:{A}, threadflag:(MT mode:Multithreaded (other), bool:true), thread:[main, t_fun@12-traces-min-rpb1.c:25:3-25:40]] (conf. 110) (exp: & h) (12-traces-min-rpb1.c:15:3-15:8) + read with [mhp:{created={[main, t_fun@12-traces-min-rpb1.c:25:3-25:40]}}, threadflag:(MT mode:Multithreaded (main), bool:true), thread:[main]] (conf. 110) (exp: & h) (12-traces-min-rpb1.c:27:3-27:26) [Warning][Race] Memory location g (race with conf. 110): (12-traces-min-rpb1.c:7:5-7:10) - write with [lock:{A}, thread:[main, t_fun@12-traces-min-rpb1.c:25:3-25:40]] (conf. 110) (exp: & g) (12-traces-min-rpb1.c:14:3-14:8) - read with [mhp:{created={[main, t_fun@12-traces-min-rpb1.c:25:3-25:40]}}, thread:[main]] (conf. 110) (exp: & g) (12-traces-min-rpb1.c:27:3-27:26) + write with [lock:{A}, threadflag:(MT mode:Multithreaded (other), bool:true), thread:[main, t_fun@12-traces-min-rpb1.c:25:3-25:40]] (conf. 110) (exp: & g) (12-traces-min-rpb1.c:14:3-14:8) + read with [mhp:{created={[main, t_fun@12-traces-min-rpb1.c:25:3-25:40]}}, threadflag:(MT mode:Multithreaded (main), bool:true), thread:[main]] (conf. 110) (exp: & g) (12-traces-min-rpb1.c:27:3-27:26) [Info][Witness] witness generation summary: location invariants: 3 loop invariants: 0 @@ -64,11 +64,11 @@ [Success][Assert] Assertion "g == h" will succeed (12-traces-min-rpb1.c:16:3-16:26) [Success][Assert] Assertion "g == h" will succeed (12-traces-min-rpb1.c:29:3-29:26) [Warning][Race] Memory location g (race with conf. 110): (12-traces-min-rpb1.c:7:5-7:10) - write with [lock:{A}, thread:[main, t_fun@12-traces-min-rpb1.c:25:3-25:40]] (conf. 110) (exp: & g) (12-traces-min-rpb1.c:14:3-14:8) - read with [mhp:{created={[main, t_fun@12-traces-min-rpb1.c:25:3-25:40]}}, thread:[main]] (conf. 110) (exp: & g) (12-traces-min-rpb1.c:27:3-27:26) + write with [lock:{A}, threadflag:(MT mode:Multithreaded (other), bool:true), thread:[main, t_fun@12-traces-min-rpb1.c:25:3-25:40]] (conf. 110) (exp: & g) (12-traces-min-rpb1.c:14:3-14:8) + read with [mhp:{created={[main, t_fun@12-traces-min-rpb1.c:25:3-25:40]}}, threadflag:(MT mode:Multithreaded (main), bool:true), thread:[main]] (conf. 110) (exp: & g) (12-traces-min-rpb1.c:27:3-27:26) [Warning][Race] Memory location h (race with conf. 110): (12-traces-min-rpb1.c:8:5-8:10) - write with [lock:{A}, thread:[main, t_fun@12-traces-min-rpb1.c:25:3-25:40]] (conf. 110) (exp: & h) (12-traces-min-rpb1.c:15:3-15:8) - read with [mhp:{created={[main, t_fun@12-traces-min-rpb1.c:25:3-25:40]}}, thread:[main]] (conf. 110) (exp: & h) (12-traces-min-rpb1.c:27:3-27:26) + write with [lock:{A}, threadflag:(MT mode:Multithreaded (other), bool:true), thread:[main, t_fun@12-traces-min-rpb1.c:25:3-25:40]] (conf. 110) (exp: & h) (12-traces-min-rpb1.c:15:3-15:8) + read with [mhp:{created={[main, t_fun@12-traces-min-rpb1.c:25:3-25:40]}}, threadflag:(MT mode:Multithreaded (main), bool:true), thread:[main]] (conf. 110) (exp: & h) (12-traces-min-rpb1.c:27:3-27:26) [Info][Race] Memory locations race summary: safe: 0 vulnerable: 0 diff --git a/tests/regression/45-escape/51-fresh-global.t b/tests/regression/45-escape/51-fresh-global.t index ceb21425e8..aa6e06e153 100644 --- a/tests/regression/45-escape/51-fresh-global.t +++ b/tests/regression/45-escape/51-fresh-global.t @@ -4,8 +4,8 @@ dead: 0 total lines: 15 [Warning][Race] Memory location (alloc@sid:$SID@tid:main) (race with conf. 110): (51-fresh-global.c:25:7-25:31) - write with lock:{A} (conf. 110) (exp: & *i) (51-fresh-global.c:10:3-10:10) - write with thread:main (conf. 110) (exp: & *i) (51-fresh-global.c:27:3-27:9) + write with [lock:{A}, threadflag:(MT mode:Multithreaded (other), bool:true)] (conf. 110) (exp: & *i) (51-fresh-global.c:10:3-10:10) + write with [threadflag:(MT mode:Multithreaded (main), bool:true), thread:main] (conf. 110) (exp: & *i) (51-fresh-global.c:27:3-27:9) [Info][Race] Memory locations race summary: safe: 1 vulnerable: 0 diff --git a/tests/regression/46-apron2/95-witness-mm-escape.t b/tests/regression/46-apron2/95-witness-mm-escape.t index 11cd3691c5..9724c1a9a9 100644 --- a/tests/regression/46-apron2/95-witness-mm-escape.t +++ b/tests/regression/46-apron2/95-witness-mm-escape.t @@ -27,3 +27,8 @@ unsupported: 0 disabled: 0 total validation entries: 15 + [Info][Race] Memory locations race summary: + safe: 1 + vulnerable: 0 + unsafe: 0 + total memory locations: 1 diff --git a/tests/regression/56-witness/68-ghost-ambiguous-idx.t b/tests/regression/56-witness/68-ghost-ambiguous-idx.t index 40025acf17..03fd9bd708 100644 --- a/tests/regression/56-witness/68-ghost-ambiguous-idx.t +++ b/tests/regression/56-witness/68-ghost-ambiguous-idx.t @@ -6,9 +6,9 @@ dead: 0 total lines: 15 [Warning][Race] Memory location data (race with conf. 110): (68-ghost-ambiguous-idx.c:4:5-4:9) - write with [lock:{m[4]}, thread:[main, t_fun@68-ghost-ambiguous-idx.c:20:3-20:40]] (conf. 110) (exp: & data) (68-ghost-ambiguous-idx.c:9:3-9:9) - write with [lock:{m[4]}, thread:[main, t_fun@68-ghost-ambiguous-idx.c:20:3-20:40]] (conf. 110) (exp: & data) (68-ghost-ambiguous-idx.c:10:3-10:9) - read with [mhp:{created={[main, t_fun@68-ghost-ambiguous-idx.c:20:3-20:40]}}, thread:[main]] (conf. 110) (exp: & data) (68-ghost-ambiguous-idx.c:24:3-24:29) + write with [lock:{m[4]}, threadflag:(MT mode:Multithreaded (other), bool:true), thread:[main, t_fun@68-ghost-ambiguous-idx.c:20:3-20:40]] (conf. 110) (exp: & data) (68-ghost-ambiguous-idx.c:9:3-9:9) + write with [lock:{m[4]}, threadflag:(MT mode:Multithreaded (other), bool:true), thread:[main, t_fun@68-ghost-ambiguous-idx.c:20:3-20:40]] (conf. 110) (exp: & data) (68-ghost-ambiguous-idx.c:10:3-10:9) + read with [mhp:{created={[main, t_fun@68-ghost-ambiguous-idx.c:20:3-20:40]}}, threadflag:(MT mode:Multithreaded (main), bool:true), thread:[main]] (conf. 110) (exp: & data) (68-ghost-ambiguous-idx.c:24:3-24:29) [Info][Witness] witness generation summary: location invariants: 0 loop invariants: 0 diff --git a/tests/regression/56-witness/69-ghost-ptr-protection.t b/tests/regression/56-witness/69-ghost-ptr-protection.t index 0c5fb0201c..c4c1f7519e 100644 --- a/tests/regression/56-witness/69-ghost-ptr-protection.t +++ b/tests/regression/56-witness/69-ghost-ptr-protection.t @@ -5,9 +5,9 @@ dead: 0 total lines: 15 [Warning][Race] Memory location p (race with conf. 110): (69-ghost-ptr-protection.c:7:5-7:12) - write with [lock:{m2}, thread:[main, t_fun@69-ghost-ptr-protection.c:22:3-22:40]] (conf. 110) (exp: & p) (69-ghost-ptr-protection.c:14:3-14:9) - write with [lock:{m2}, thread:[main, t_fun@69-ghost-ptr-protection.c:22:3-22:40]] (conf. 110) (exp: & p) (69-ghost-ptr-protection.c:15:3-15:9) - read with [mhp:{created={[main, t_fun@69-ghost-ptr-protection.c:22:3-22:40]}}, lock:{m1}, thread:[main]] (conf. 110) (exp: & p) (69-ghost-ptr-protection.c:26:3-26:27) + write with [lock:{m2}, threadflag:(MT mode:Multithreaded (other), bool:true), thread:[main, t_fun@69-ghost-ptr-protection.c:22:3-22:40]] (conf. 110) (exp: & p) (69-ghost-ptr-protection.c:14:3-14:9) + write with [lock:{m2}, threadflag:(MT mode:Multithreaded (other), bool:true), thread:[main, t_fun@69-ghost-ptr-protection.c:22:3-22:40]] (conf. 110) (exp: & p) (69-ghost-ptr-protection.c:15:3-15:9) + read with [mhp:{created={[main, t_fun@69-ghost-ptr-protection.c:22:3-22:40]}}, lock:{m1}, threadflag:(MT mode:Multithreaded (main), bool:true), thread:[main]] (conf. 110) (exp: & p) (69-ghost-ptr-protection.c:26:3-26:27) [Info][Witness] witness generation summary: location invariants: 0 loop invariants: 0 @@ -124,9 +124,9 @@ Same with vojdani. dead: 0 total lines: 15 [Warning][Race] Memory location p (race with conf. 110): (69-ghost-ptr-protection.c:7:5-7:12) - write with [lock:{m2}, thread:[main, t_fun@69-ghost-ptr-protection.c:22:3-22:40]] (conf. 110) (exp: & p) (69-ghost-ptr-protection.c:14:3-14:9) - write with [lock:{m2}, thread:[main, t_fun@69-ghost-ptr-protection.c:22:3-22:40]] (conf. 110) (exp: & p) (69-ghost-ptr-protection.c:15:3-15:9) - read with [mhp:{created={[main, t_fun@69-ghost-ptr-protection.c:22:3-22:40]}}, lock:{m1}, thread:[main]] (conf. 110) (exp: & p) (69-ghost-ptr-protection.c:26:3-26:27) + write with [lock:{m2}, threadflag:(MT mode:Multithreaded (other), bool:true), thread:[main, t_fun@69-ghost-ptr-protection.c:22:3-22:40]] (conf. 110) (exp: & p) (69-ghost-ptr-protection.c:14:3-14:9) + write with [lock:{m2}, threadflag:(MT mode:Multithreaded (other), bool:true), thread:[main, t_fun@69-ghost-ptr-protection.c:22:3-22:40]] (conf. 110) (exp: & p) (69-ghost-ptr-protection.c:15:3-15:9) + read with [mhp:{created={[main, t_fun@69-ghost-ptr-protection.c:22:3-22:40]}}, lock:{m1}, threadflag:(MT mode:Multithreaded (main), bool:true), thread:[main]] (conf. 110) (exp: & p) (69-ghost-ptr-protection.c:26:3-26:27) [Info][Witness] witness generation summary: location invariants: 0 loop invariants: 0 diff --git a/tests/regression/74-invalid_deref/01-oob-heap-simple.t b/tests/regression/74-invalid_deref/01-oob-heap-simple.t index ac3ec99fa8..0f241692cd 100644 --- a/tests/regression/74-invalid_deref/01-oob-heap-simple.t +++ b/tests/regression/74-invalid_deref/01-oob-heap-simple.t @@ -6,6 +6,11 @@ live: 8 dead: 0 total lines: 8 + [Info][Race] Memory locations race summary: + safe: 2 + vulnerable: 0 + unsafe: 0 + total memory locations: 2 $ goblint --set ana.activated[+] memOutOfBounds --enable ana.int.interval --enable dbg.full-output 01-oob-heap-simple.c > full-output.txt 2>&1 From 6c0f9fd0f23b7439f5f712936dd2d0bf0fef3583 Mon Sep 17 00:00:00 2001 From: Michael Schwarz Date: Wed, 28 May 2025 19:57:06 +0200 Subject: [PATCH 49/68] TID+Join --- conf/race-digests/tid+join.json | 128 ++++++++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 conf/race-digests/tid+join.json diff --git a/conf/race-digests/tid+join.json b/conf/race-digests/tid+join.json new file mode 100644 index 0000000000..55382576e0 --- /dev/null +++ b/conf/race-digests/tid+join.json @@ -0,0 +1,128 @@ +{ + "ana": { + "sv-comp": { + "enabled": true, + "functions": true + }, + "int": { + "def_exc": true, + "enums": false, + "interval": true + }, + "float": { + "interval": true, + "evaluate_math_functions": true + }, + "activated": [ + "base", + "threadid", + "threadflag", + "threadreturn", + "mallocWrapper", + "mutexEvents", + "mutex", + "access", + "race", + "escape", + "expRelation", + "mhp", + "assert", + "var_eq", + "symb_locks", + "region", + "thread", + "threadJoins", + "abortUnless" + ], + "path_sens": [ + "mutex", + "malloc_null", + "uninit", + "expsplit", + "activeSetjmp", + "memLeak", + "threadflag" + ], + "context": { + "widen": false + }, + "base": { + "arrays": { + "domain": "partitioned" + } + }, + "race": { + "free": false, + "call": false, + "digests": { + "lockset": false, + + "fresh": false, + "region": false, + "symb_locks": false, + "threadflag": false, + "tid": true, + "join" : true + } + }, + "autotune": { + "enabled": true, + "activated": [ + "singleThreaded", + "mallocWrappers", + "noRecursiveIntervals", + "enums", + "congruence", + "octagon", + "wideningThresholds", + "loopUnrollHeuristic", + "memsafetySpecification", + "noOverflows", + "termination", + "tmpSpecialAnalysis" + ] + } + }, + "exp": { + "region-offsets": true + }, + "solver": "td3", + "sem": { + "unknown_function": { + "spawn": false + }, + "int": { + "signed_overflow": "assume_none" + }, + "null-pointer": { + "dereference": "assume_none" + } + }, + "witness": { + "graphml": { + "enabled": true, + "id": "enumerate", + "unknown": false + }, + "yaml": { + "enabled": true, + "format-version": "2.0", + "entry-types": [ + "invariant_set" + ], + "invariant-types": [ + "loop_invariant" + ] + }, + "invariant": { + "loop-head": true, + "after-lock": false, + "other": false, + "accessed": false, + "exact": true + } + }, + "pre": { + "enabled": false + } +} From bc4b34c9c9d033b0f4023cf32535ee286d9d77c0 Mon Sep 17 00:00:00 2001 From: Michael Schwarz Date: Sat, 31 May 2025 17:13:16 +0200 Subject: [PATCH 50/68] Add tests --- tests/regression/83-once/05-unknown-tid.c | 28 ++++++++++++ .../83-once/06-multiple-inside-once.c | 27 +++++++++++ tests/regression/83-once/07-different-onces.c | 29 ++++++++++++ tests/regression/83-once/08-pointers.c | 39 ++++++++++++++++ tests/regression/83-once/09-pointers2.c | 38 ++++++++++++++++ tests/regression/83-once/10-pointer-once.c | 33 ++++++++++++++ tests/regression/83-once/11-combination.c | 45 +++++++++++++++++++ 7 files changed, 239 insertions(+) create mode 100644 tests/regression/83-once/05-unknown-tid.c create mode 100644 tests/regression/83-once/06-multiple-inside-once.c create mode 100644 tests/regression/83-once/07-different-onces.c create mode 100644 tests/regression/83-once/08-pointers.c create mode 100644 tests/regression/83-once/09-pointers2.c create mode 100644 tests/regression/83-once/10-pointer-once.c create mode 100644 tests/regression/83-once/11-combination.c diff --git a/tests/regression/83-once/05-unknown-tid.c b/tests/regression/83-once/05-unknown-tid.c new file mode 100644 index 0000000000..f6aa7956ba --- /dev/null +++ b/tests/regression/83-once/05-unknown-tid.c @@ -0,0 +1,28 @@ +// PARAM: --set ana.activated[+] pthreadOnce +#include +#include + +int g; +pthread_once_t once = PTHREAD_ONCE_INIT; +pthread_mutex_t mutex1 = PTHREAD_MUTEX_INITIALIZER; + +void fun() { + g++; //NORACE +} + + +void* thread(void* arg) { + pthread_once(&once, fun); + return NULL; +} + +int main(void) { + pthread_t id; + + for(int i=0; i < 100; i++) { + // Will receive unknown TID + pthread_create(&id, NULL, thread, NULL); + } + + return 0; +} diff --git a/tests/regression/83-once/06-multiple-inside-once.c b/tests/regression/83-once/06-multiple-inside-once.c new file mode 100644 index 0000000000..b388c85963 --- /dev/null +++ b/tests/regression/83-once/06-multiple-inside-once.c @@ -0,0 +1,27 @@ +// PARAM: --set ana.activated[+] pthreadOnce +#include +#include + +int g; +pthread_once_t once = PTHREAD_ONCE_INIT; +pthread_mutex_t mutex1 = PTHREAD_MUTEX_INITIALIZER; + +void fun() { + g++; //NORACE + g++; //NORACE +} + + +void* thread(void* arg) { + pthread_once(&once, fun); + return NULL; +} + +int main(void) { + pthread_t id; + + pthread_create(&id, NULL, thread, NULL); + pthread_once(&once, fun); + + return 0; +} diff --git a/tests/regression/83-once/07-different-onces.c b/tests/regression/83-once/07-different-onces.c new file mode 100644 index 0000000000..7e9bf83968 --- /dev/null +++ b/tests/regression/83-once/07-different-onces.c @@ -0,0 +1,29 @@ +// PARAM: --set ana.activated[+] pthreadOnce +// Developer used tow different pthread_once_t variables by mistake +#include +#include + +int g; +pthread_once_t once = PTHREAD_ONCE_INIT; +pthread_once_t once1 = PTHREAD_ONCE_INIT; +pthread_mutex_t mutex1 = PTHREAD_MUTEX_INITIALIZER; + +void fun() { + g++; //RACE! + g++; //RACE! +} + + +void* thread(void* arg) { + pthread_once(&once, fun); + return NULL; +} + +int main(void) { + pthread_t id; + + pthread_create(&id, NULL, thread, NULL); + pthread_once(&once1, fun); + + return 0; +} diff --git a/tests/regression/83-once/08-pointers.c b/tests/regression/83-once/08-pointers.c new file mode 100644 index 0000000000..b2df8c6c05 --- /dev/null +++ b/tests/regression/83-once/08-pointers.c @@ -0,0 +1,39 @@ +// PARAM: --set ana.activated[+] pthreadOnce +// Function to be called by once is passed as a pointer +#include +#include + +int g; +void init0(); + +void* initp = &init0; +pthread_once_t once = PTHREAD_ONCE_INIT; +pthread_mutex_t mutex1 = PTHREAD_MUTEX_INITIALIZER; + +void init0() { + g++; //NORACE +} + + +void init1() { + g++; //NORACE +} + + +void* thread(void* arg) { + pthread_once(&once, initp); + return NULL; +} + +int main(void) { + pthread_t id; + int top; + + if(top) { initp = &init1; } + + pthread_create(&id, NULL, thread, NULL); + + pthread_once(&once, initp); + + return 0; +} diff --git a/tests/regression/83-once/09-pointers2.c b/tests/regression/83-once/09-pointers2.c new file mode 100644 index 0000000000..3cf93c19a1 --- /dev/null +++ b/tests/regression/83-once/09-pointers2.c @@ -0,0 +1,38 @@ +// PARAM: --set ana.activated[+] pthreadOnce +// Function to be called by once is passed as a pointer +#include +#include + +int g; +void init0(); + +void* initp = &init0; +pthread_once_t once = PTHREAD_ONCE_INIT; +pthread_mutex_t mutex1 = PTHREAD_MUTEX_INITIALIZER; + +void init0() { + g++; //NORACE +} + + +void init1() { + g++; //NORACE +} + + +void* thread(void* arg) { + pthread_once(&once, initp); + return NULL; +} + +int main(void) { + pthread_t id; + int top; + + pthread_create(&id, NULL, thread, NULL); + if(top) { initp = &init1; } + pthread_once(&once, initp); + + + return 0; +} diff --git a/tests/regression/83-once/10-pointer-once.c b/tests/regression/83-once/10-pointer-once.c new file mode 100644 index 0000000000..c074c55994 --- /dev/null +++ b/tests/regression/83-once/10-pointer-once.c @@ -0,0 +1,33 @@ +// PARAM: --set ana.activated[+] pthreadOnce +// pthread_once object is passed as a pointer (and it may change) +#include +#include + +int g; +void init0(); + +pthread_once_t* optr; +pthread_once_t once = PTHREAD_ONCE_INIT; +pthread_once_t once1 = PTHREAD_ONCE_INIT; +pthread_mutex_t mutex1 = PTHREAD_MUTEX_INITIALIZER; + +void init0() { + g++; //RACE +} + + +void* thread(void* arg) { + pthread_once(&once, init0); + return NULL; +} + +int main(void) { + pthread_t id; + int top; + + pthread_create(&id, NULL, thread, NULL); + if(top) { optr = &once1; } + pthread_once(optr, init0); + + return 0; +} diff --git a/tests/regression/83-once/11-combination.c b/tests/regression/83-once/11-combination.c new file mode 100644 index 0000000000..f7e943f80c --- /dev/null +++ b/tests/regression/83-once/11-combination.c @@ -0,0 +1,45 @@ +// PARAM: --set ana.activated[+] pthreadOnce --set ana.activated[+] threadJoins --set ana.path_sens[+] threadflag --set ana.base.privatization mutex-meet-tid +// pthread_once object is passed as a pointer (and it may change) +#include +#include + +int* g; +pthread_once_t once = PTHREAD_ONCE_INIT; +pthread_mutex_t mtx; + +void init0() { + g = malloc(sizeof(int)); +} + + +void* thread(void* arg) { + pthread_once(&once, init0); + + pthread_mutex_lock(&mtx); + if(g == NULL) { + // Will not happen! + // Also showing that g is not NULL here requires "Extended Support for pthread once" as explained in appendix C. + // It was added manually here so we can show off that at the end we can exclude the in initial value even + // though main didn't write + exit(); + } + *g = 4711; //NORACE + pthread_mutex_unlock(&mtx); + + return NULL; +} + +int main(void) { + pthread_t id, id2; + int top; + + pthread_create(&id, NULL, thread, NULL); + pthread_create(&id2, NULL, thread, NULL); + + pthread_join(id, NULL); + pthread_join(id2, NULL); + + *g = 47; //NORACE + + return 0; +} From 52e7660a160efff33b430442b56222003b88b2a8 Mon Sep 17 00:00:00 2001 From: Michael Schwarz Date: Thu, 11 Sep 2025 09:20:30 +0800 Subject: [PATCH 51/68] Make setup less strict --- make.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/make.sh b/make.sh index fddbf73ae0..a5d1691fd8 100755 --- a/make.sh +++ b/make.sh @@ -8,7 +8,7 @@ opam_setup() { set -x opam init -y -a --bare $SANDBOXING # sandboxing is disabled in travis and docker opam update - opam switch -y create . --deps-only --packages=ocaml-variants.4.14.2+options,ocaml-option-flambda --locked + opam switch -y create . --deps-only --packages=ocaml-variants.4.14.2+options,ocaml-option-flambda } rule() { @@ -81,7 +81,7 @@ rule() { ;; dev) eval $(opam env) echo "Installing opam packages for test and doc..." - opam install -y . --deps-only --locked --with-test --with-doc + opam install -y . --deps-only --with-test --with-doc echo "Installing opam packages for development..." opam install -y ocaml-lsp-server ocp-indent # ocaml-lsp-server is needed for https://github.com/ocamllabs/vscode-ocaml-platform From 594757d23704ec93df534af357ee8be0044653c6 Mon Sep 17 00:00:00 2001 From: Michael Schwarz Date: Thu, 11 Sep 2025 09:25:52 +0800 Subject: [PATCH 52/68] Rename general README --- README.md => GOBLINT_README.md | 2 ++ 1 file changed, 2 insertions(+) rename README.md => GOBLINT_README.md (97%) diff --git a/README.md b/GOBLINT_README.md similarity index 97% rename from README.md rename to GOBLINT_README.md index 6aee964826..45ae104f7f 100644 --- a/README.md +++ b/GOBLINT_README.md @@ -1,3 +1,5 @@ +**This is the README for the entire Goblint system, when getting started with the artifact, it is best to look at README.md** + # Goblint [![GitHub release status](https://img.shields.io/github/v/release/goblint/analyzer)](https://github.com/goblint/analyzer/releases) [![opam package status](https://badgen.net/opam/v/goblint)](https://opam.ocaml.org/packages/goblint) From c4e6f7352814098350e89e7f774c747561faf7b2 Mon Sep 17 00:00:00 2001 From: Michael Schwarz Date: Thu, 11 Sep 2025 09:46:26 +0800 Subject: [PATCH 53/68] Rm test problematic because of preprocessing --- tests/regression/83-once/11-combination.c | 45 ----------------------- 1 file changed, 45 deletions(-) delete mode 100644 tests/regression/83-once/11-combination.c diff --git a/tests/regression/83-once/11-combination.c b/tests/regression/83-once/11-combination.c deleted file mode 100644 index f7e943f80c..0000000000 --- a/tests/regression/83-once/11-combination.c +++ /dev/null @@ -1,45 +0,0 @@ -// PARAM: --set ana.activated[+] pthreadOnce --set ana.activated[+] threadJoins --set ana.path_sens[+] threadflag --set ana.base.privatization mutex-meet-tid -// pthread_once object is passed as a pointer (and it may change) -#include -#include - -int* g; -pthread_once_t once = PTHREAD_ONCE_INIT; -pthread_mutex_t mtx; - -void init0() { - g = malloc(sizeof(int)); -} - - -void* thread(void* arg) { - pthread_once(&once, init0); - - pthread_mutex_lock(&mtx); - if(g == NULL) { - // Will not happen! - // Also showing that g is not NULL here requires "Extended Support for pthread once" as explained in appendix C. - // It was added manually here so we can show off that at the end we can exclude the in initial value even - // though main didn't write - exit(); - } - *g = 4711; //NORACE - pthread_mutex_unlock(&mtx); - - return NULL; -} - -int main(void) { - pthread_t id, id2; - int top; - - pthread_create(&id, NULL, thread, NULL); - pthread_create(&id2, NULL, thread, NULL); - - pthread_join(id, NULL); - pthread_join(id2, NULL); - - *g = 47; //NORACE - - return 0; -} From 074734e0d30f72ac981c304d4588c2226abf987d Mon Sep 17 00:00:00 2001 From: Michael Schwarz Date: Thu, 11 Sep 2025 09:54:17 +0800 Subject: [PATCH 54/68] Getting started on a README --- .gitignore | 1 + README.md | 165 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 166 insertions(+) create mode 100644 README.md diff --git a/.gitignore b/.gitignore index 7038e51f8f..d13f6fbc01 100644 --- a/.gitignore +++ b/.gitignore @@ -23,6 +23,7 @@ doclist.odocl autom4te.cache mytests result/* +results/* pml-result/* tests/regression/*/goblint_temp linux-headers diff --git a/README.md b/README.md new file mode 100644 index 0000000000..025cedf165 --- /dev/null +++ b/README.md @@ -0,0 +1,165 @@ +# Artifact Description +## Data Race Detection by Digest-Driven Abstract Intepretation + +This is the artifact description for our manuscript **Data Race Detection by Digest-Driven Abstract Intepretation**. + +The artifact contains [Goblint at `race_digest_staging` branch](https://github.com/goblint/analyzer/tree/race_digest_staging). + + +## Overview + +This artifact contains the following components: + + Evaluation Results :: The evaluation results, and overview tables (HTML) + generated from the raw data. + Source Code :: Source code for Goblint. + Verifier Binary :: Binary for Goblint. + Benchmark Programs :: Benchmarks used for evaluation (SV-COMP 2025). + BenchExec Tool :: The BenchExec benchmarking tool can be used + to replicate our results on these benchmarks. + +The next section gives instructions on how to setup and quickly get an overview of the artifact. +The subsequent sections then describe each of these components in detail. +The final section gives information on how to reuse this artifact. + + +## Getting Started + +### 1. Setup + +The artifact is a virtual machine (VM), as the Benchexec system used for reliable benchmarking cannot be installed in docker images. The machine is intended for an x86 machine, behavior on M1 chips is untested. +Follow these steps to set it up: + +* If you have not done so already, install VirtualBox. + () +* Download the artifact. +* Import the artifact via the VirtualBox UI (`File > Import Appliance`). + +You can then start the VM from the VirtualBox UI. +Login with user `goblint` and password `goblint`. + +### 2. Inspect the evaluation results + + + +### 3. Quick Test of the Benchmark Setup + +To check Goblint is properly installed, run + + cd ~/analyzer + make sanitytest + +on a console in the VM. +The run should take no longer than 2 minutes, the expected output is + + Excellent: ignored check on tests/regression/03-practical/21-pfscan_combine_minimal.c:21 is now passing! + Excellent: ignored check on tests/regression/03-practical/21-pfscan_combine_minimal.c:29 is now passing! + No errors :) + + + +### 4. Running the Full Experiments + +To re-run the full experiments, execute + + ~/scripts/full-run.sh + +This script behaves similarly to the smaller variants in the previous sections. +Note however: + +- By default the experiments require 16 GB of memory per benchmark (this configuration was used for the experiments in the paper). + To reproduce this, you will have to modify the VM's settings in VirtualBox and increase the available memory (shutdown the machine while doing so). + + Alternatively, you can run the experiments with a reduced memory limit. + To do so, modify the environment variable `BENCHMARK_PARAMS`. + For instance, the following allows only 4GB of memory per benchmark: + + BENCHMARK_PARAMS="-M 4GB" ~/scripts/full-run.sh + +- The full evaluation for the paper required around 3 days. + In this evaluation, we used the benchexec tool to run 14 validation tasks in parallel (occupying up to 28 cores at a time). + + By default, the provided script only runs one benchmark at a time. + If you have sufficient cores and memory available (adjust the VM settings accordingly), you can run multiple benchmarks in parallel by setting the environment variable `BENCHEXEC_THREADS`. You may also execute the experiments with a reduced timeout. + For instance, the following command runs 4 benchmarks in parallel at a time (occupying up to 8 cores), and gives each benchmark a 300s timeout and 4GB memory limit: + + BENCHEXEC_THREADS=4 BENCHMARK_PARAMS="-T 300s -M 4GB" ~/scripts/full-run.sh + +Naturally, changes to the timeout or memory are expected to affect the evaluation numbers. + + +## Evaluation Results + +The evaluation results that form the basis for the experimental data in the paper can be found in the directory `~/witness-validation/paper-evaluation/`. +The witnesses generated by Goblint that formed the basis for this evaluation can be found in `~/witness-generation/paper-evaluation/`. +See below for detailed info to reproduce the tables and figures of the paper. + +The file `~/witness-validation/paper-evaluation/` contains an HTML overview page generated by the BenchExec benchmarking tool, which displays individual results, quantile and scatter plots. Through the filtering sidebar (top right corner), detailed analyses can be made. + +The table contains the following configurations : + +* `verify` -- GemCutter verification, without any witness +* `verify+validate-goblint-witnesses-{mutex-meet,protection}-{ghost,local}` -- GemCutter witness validation, applied to the 4 different witness sets generated by Goblint. + In this mode, GemCutter checks if the given witness is valid and the corresponding program is correct. +* `validate-goblint-witnesses-{mutex-meet,protection}-{ghost,local}` -- GemCutter witness _confirmation_, applied to the different witness sets. + In this mode, described in the paper, GemCutter only checks if the given witness' invariants are correct, but does not prove the corresponding program correct. + +The summary table shows how many benchmarks were analysed and the results. + +- The row `correct true` indicates tasks that were successfully verified (for `verify`), or where the witness was confirmed resp. validated (for the other configurations). +- The row `correct false` indicates that a bug was found (for `verify`), resp. that witness validation failed and a witness was rejected. + The latter only happens for programs that are incorrect, hence there can be no valid correctness witness and rejection is expected. + As witness validation is not possible for incorrect programs, this data is not discussed in the paper and only appears here due to the benchmark setup. +- The row `incorrect false` would indicate that GemCutter finds a supposed bug in a correct program (for `verify`). + For witness confirmation configurations, it indicates that GemCutter confirmed the correctness witness given by Goblint, for an incorrect program. + As witness confirmation ignores the program's correctness, these results are expected and do not indicate a problem in one of the tools. + +The *Table* tab gives access to detailed evaluation results for each file. +Clicking on a status shows the complete GemCutter log for the benchmark run. + +> **Note:** If you are trying to view logs for individual runs through the HTML table (by clicking on the evaluation result `true` or `false`), you may encounter a warning because browsers block access to local files. Follow the instructions in the message to enable log viewing. + +As described above (in [section _2. Inspect the evaluation results_](#2-inspect-the-evaluation-results)), the artifact provides python scripts to directly extract the data shown in the paper from the benchmark results. + + +## Source Code + + +### Goblint + +The Goblint analyzer () is developed by TU Munich and University of Tartu. The source code for Goblint at the time of evaluation can be found in this artifact in the `~/analyzer` directory. + +The code for this paper is the following: + +**TODO** + +More recent versions of Goblint can be found at . + + +## Verifier Binaries + +A pre-built binary of Goblint is available as `~/analzyer/goblint`. +See `~/analyzer/GOBLINT_README.md` for information on how to run Goblint. +To build Goblint from scratch, run `make release`. + + +## Benchmark Programs + +This artifact includes the benchmark programs on which we evaluated the verifiers. +These benchmarks are taken from the publicly available sv-benchmarks set () +and correspond to the _ConcurrencySafety-Main_ category of SV-COMP'24 (). +The benchmarks are written in C and use POSIX threads (`pthreads`) to model concurrency. + + +## Extending & Reusing This Artifact + +* **Adding benchmarks:** You can easily add your own benchmarks programs written in C. + C programs should contain an empty function called `reach_error()`. Goblint and GemCutter then check that this function is never invoked. Certain (gcc) preprocessing steps may be necessary, e.g. to resolve `#include`s. See the SV-COMP benchmarks for examples (the preprocessed files typically have the extension `.i`). + + To run the evaluation on your own programs, you must edit the benchmark definition files `~/witness-generation/goblint.xml.template` resp. `~/witness-validation/gemcutter.xml.template`. + Replace the `` path specified in the task set `minimal` with your own path. + You can then simply run `~/scripts/quick-run.sh`. + +## Acknowledgment + +This description is based, in part, on earlier artifact descriptions for the Goblint system, in particular of our VMCAI '24 & '25 and ESOP '23 papers. \ No newline at end of file From 1fa5b4fa11ac91bf3b5694cd662b33d6ab14496f Mon Sep 17 00:00:00 2001 From: Michael Schwarz Date: Fri, 12 Sep 2025 12:26:57 +0800 Subject: [PATCH 55/68] Artifacting --- README.md | 58 +++++++++++++++++++++++++++++++------------------------ 1 file changed, 33 insertions(+), 25 deletions(-) diff --git a/README.md b/README.md index 025cedf165..248b1d8b1a 100644 --- a/README.md +++ b/README.md @@ -38,13 +38,9 @@ Follow these steps to set it up: You can then start the VM from the VirtualBox UI. Login with user `goblint` and password `goblint`. -### 2. Inspect the evaluation results +### 2. Quick Test of the Benchmark Setup - - -### 3. Quick Test of the Benchmark Setup - -To check Goblint is properly installed, run +To check Goblint is properly installed, run cd ~/analyzer make sanitytest @@ -56,6 +52,8 @@ The run should take no longer than 2 minutes, the expected output is Excellent: ignored check on tests/regression/03-practical/21-pfscan_combine_minimal.c:29 is now passing! No errors :) +You can also run the analysis for a subset of tasks and configurations by executing: + ### 4. Running the Full Experiments @@ -90,29 +88,39 @@ Naturally, changes to the timeout or memory are expected to affect the evaluatio ## Evaluation Results -The evaluation results that form the basis for the experimental data in the paper can be found in the directory `~/witness-validation/paper-evaluation/`. -The witnesses generated by Goblint that formed the basis for this evaluation can be found in `~/witness-generation/paper-evaluation/`. -See below for detailed info to reproduce the tables and figures of the paper. +This evaluation supports all _experimental_ claims made in Section 7. Please note that Table 1 is not based on our experiments, but cited from the report on SV-COMP 2025. + +All claims can be verified by opening the tables generated by the steps outlined in (4. Running the Full Experiments) which are located in **TODO**. +If results were only generated for some configs in that step, the remaining results can be verified using the tables located in **TODO** from our run inside the artifact. + +These are HTML overviews as generated by the BenchExec benchmarking tool. + +The table contains one configuration for every column of the table in Fig. 8 which are named by the activated digests. + +- The row `correct true` indicates tasks where race-freedom was correctly established. +- The row `correct false` indicates tasks that were correctly identified as racy. (Goblint can't do this, always 0) +- The row `incorrect true` indicates false negatives, i.e., cases where race-freedom was claimed, even though the program is racy. +- The row `incorrect false` indicates false positives, i.e., cases where the definite presence of a race was claimed, but there is none. (Goblint never claims that a program must be racy, always 0) + + +### How the claims are supported by this table: + +> Fig. 8 + +The numbers in Fig. 8 can be directly read off from this table. + + +> None of the approaches produced any false negatives for the other 235 tasks in the benchmark set, which are racy. + +Can be verified by checking that the `incorrect true` number for all configurations is zero. + -The file `~/witness-validation/paper-evaluation/` contains an HTML overview page generated by the BenchExec benchmarking tool, which displays individual results, quantile and scatter plots. Through the filtering sidebar (top right corner), detailed analyses can be made. +> Discussion in ln. 546ff -The table contains the following configurations : +Refers only to numbers in Fig. 8. -* `verify` -- GemCutter verification, without any witness -* `verify+validate-goblint-witnesses-{mutex-meet,protection}-{ghost,local}` -- GemCutter witness validation, applied to the 4 different witness sets generated by Goblint. - In this mode, GemCutter checks if the given witness is valid and the corresponding program is correct. -* `validate-goblint-witnesses-{mutex-meet,protection}-{ghost,local}` -- GemCutter witness _confirmation_, applied to the different witness sets. - In this mode, described in the paper, GemCutter only checks if the given witness' invariants are correct, but does not prove the corresponding program correct. -The summary table shows how many benchmarks were analysed and the results. -- The row `correct true` indicates tasks that were successfully verified (for `verify`), or where the witness was confirmed resp. validated (for the other configurations). -- The row `correct false` indicates that a bug was found (for `verify`), resp. that witness validation failed and a witness was rejected. - The latter only happens for programs that are incorrect, hence there can be no valid correctness witness and rejection is expected. - As witness validation is not possible for incorrect programs, this data is not discussed in the paper and only appears here due to the benchmark setup. -- The row `incorrect false` would indicate that GemCutter finds a supposed bug in a correct program (for `verify`). - For witness confirmation configurations, it indicates that GemCutter confirmed the correctness witness given by Goblint, for an incorrect program. - As witness confirmation ignores the program's correctness, these results are expected and do not indicate a problem in one of the tools. The *Table* tab gives access to detailed evaluation results for each file. Clicking on a status shows the complete GemCutter log for the benchmark run. @@ -162,4 +170,4 @@ The benchmarks are written in C and use POSIX threads (`pthreads`) to model conc ## Acknowledgment -This description is based, in part, on earlier artifact descriptions for the Goblint system, in particular of our VMCAI '24 & '25 and ESOP '23 papers. \ No newline at end of file +This description is based, in part, on earlier artifact descriptions for the Goblint system, in particular of our VMCAI'24, VMCAI'25 and ESOP'23 papers. From 3c5383b9592cc9f0c46afe976849e1f3048a4964 Mon Sep 17 00:00:00 2001 From: Michael Schwarz Date: Fri, 12 Sep 2025 12:34:50 +0800 Subject: [PATCH 56/68] Progress on README --- README.md | 48 ++++++++++++------------------------------------ 1 file changed, 12 insertions(+), 36 deletions(-) diff --git a/README.md b/README.md index 248b1d8b1a..c7fa0f7b37 100644 --- a/README.md +++ b/README.md @@ -58,33 +58,6 @@ You can also run the analysis for a subset of tasks and configurations by execut ### 4. Running the Full Experiments -To re-run the full experiments, execute - - ~/scripts/full-run.sh - -This script behaves similarly to the smaller variants in the previous sections. -Note however: - -- By default the experiments require 16 GB of memory per benchmark (this configuration was used for the experiments in the paper). - To reproduce this, you will have to modify the VM's settings in VirtualBox and increase the available memory (shutdown the machine while doing so). - - Alternatively, you can run the experiments with a reduced memory limit. - To do so, modify the environment variable `BENCHMARK_PARAMS`. - For instance, the following allows only 4GB of memory per benchmark: - - BENCHMARK_PARAMS="-M 4GB" ~/scripts/full-run.sh - -- The full evaluation for the paper required around 3 days. - In this evaluation, we used the benchexec tool to run 14 validation tasks in parallel (occupying up to 28 cores at a time). - - By default, the provided script only runs one benchmark at a time. - If you have sufficient cores and memory available (adjust the VM settings accordingly), you can run multiple benchmarks in parallel by setting the environment variable `BENCHEXEC_THREADS`. You may also execute the experiments with a reduced timeout. - For instance, the following command runs 4 benchmarks in parallel at a time (occupying up to 8 cores), and gives each benchmark a 300s timeout and 4GB memory limit: - - BENCHEXEC_THREADS=4 BENCHMARK_PARAMS="-T 300s -M 4GB" ~/scripts/full-run.sh - -Naturally, changes to the timeout or memory are expected to affect the evaluation numbers. - ## Evaluation Results @@ -120,22 +93,25 @@ Can be verified by checking that the `incorrect true` number for all configurati Refers only to numbers in Fig. 8. +> With these settings, the system ran out of memory for 4 tasks, 3 tasks timed out, and the analyzer crashed for 7 tasks. +The numbers in the VM are essentially the same as those on the server as Goblint is inherently single-threaded, and each of the cores of the server is not too powerful. Our run inside the VM matched exactly these numbers, however, some wiggle between machines is to be expected. -The *Table* tab gives access to detailed evaluation results for each file. -Clicking on a status shows the complete GemCutter log for the benchmark run. -> **Note:** If you are trying to view logs for individual runs through the HTML table (by clicking on the evaluation result `true` or `false`), you may encounter a warning because browsers block access to local files. Follow the instructions in the message to enable log viewing. -As described above (in [section _2. Inspect the evaluation results_](#2-inspect-the-evaluation-results)), the artifact provides python scripts to directly extract the data shown in the paper from the benchmark results. +> Where execution terminated, it did so within at most 20s, where for all but 6 tasks the runtime was below 10s. +The same caveat as above applies here too. -## Source Code +The *Table* tab gives access to detailed evaluation results for each file.Clicking on a status shows the complete log for the benchmark run. -### Goblint +> **Note:** If you are trying to view logs for individual runs through the HTML table (by clicking on the evaluation result `true` or `false`), you may encounter a warning because browsers block access to local files. Follow the instructions in the message to enable log viewing. + + +## Source Code -The Goblint analyzer () is developed by TU Munich and University of Tartu. The source code for Goblint at the time of evaluation can be found in this artifact in the `~/analyzer` directory. +The Goblint analyzer () is developed by Technical University of Munich and University of Tartu with one of the authors recently having moved from TUM to National University of Singapore. The source code for Goblint at the time of evaluation can be found in this artifact in the `~/analyzer` directory. The code for this paper is the following: @@ -161,7 +137,7 @@ The benchmarks are written in C and use POSIX threads (`pthreads`) to model conc ## Extending & Reusing This Artifact -* **Adding benchmarks:** You can easily add your own benchmarks programs written in C. +* **Adding benchmarks:** You can easily add your own benchmarks programs written in C. **TODO!!!** C programs should contain an empty function called `reach_error()`. Goblint and GemCutter then check that this function is never invoked. Certain (gcc) preprocessing steps may be necessary, e.g. to resolve `#include`s. See the SV-COMP benchmarks for examples (the preprocessed files typically have the extension `.i`). To run the evaluation on your own programs, you must edit the benchmark definition files `~/witness-generation/goblint.xml.template` resp. `~/witness-validation/gemcutter.xml.template`. @@ -170,4 +146,4 @@ The benchmarks are written in C and use POSIX threads (`pthreads`) to model conc ## Acknowledgment -This description is based, in part, on earlier artifact descriptions for the Goblint system, in particular of our VMCAI'24, VMCAI'25 and ESOP'23 papers. +This description is based, in part, on earlier artifact descriptions involving the Goblint system, in particular of our VMCAI'24, VMCAI'25 and ESOP'23 papers. From c86fa366d5e055b624684560206d6997d3d75988 Mon Sep 17 00:00:00 2001 From: Michael Schwarz Date: Fri, 12 Sep 2025 13:00:04 +0800 Subject: [PATCH 57/68] Explanation --- README.md | 33 ++++++++++++++++++++++++++++----- 1 file changed, 28 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index c7fa0f7b37..526dc7bc1d 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,6 @@ This is the artifact description for our manuscript **Data Race Detection by Dig The artifact contains [Goblint at `race_digest_staging` branch](https://github.com/goblint/analyzer/tree/race_digest_staging). - ## Overview This artifact contains the following components: @@ -104,7 +103,7 @@ The numbers in the VM are essentially the same as those on the server as Goblint The same caveat as above applies here too. -The *Table* tab gives access to detailed evaluation results for each file.Clicking on a status shows the complete log for the benchmark run. +The *Table* tab gives access to detailed evaluation results for each file. Clicking on a status shows the complete log for the benchmark run. > **Note:** If you are trying to view logs for individual runs through the HTML table (by clicking on the evaluation result `true` or `false`), you may encounter a warning because browsers block access to local files. Follow the instructions in the message to enable log viewing. @@ -113,9 +112,33 @@ The *Table* tab gives access to detailed evaluation results for each file.Clicki The Goblint analyzer () is developed by Technical University of Munich and University of Tartu with one of the authors recently having moved from TUM to National University of Singapore. The source code for Goblint at the time of evaluation can be found in this artifact in the `~/analyzer` directory. -The code for this paper is the following: +For an explanation of the general structure of the system, please refer to the online documentation of the system: https://goblint.readthedocs.io/en/latest/ + +The type of code particularly relevant for this paper is best illustrated along an example: + - A digest (lightweight thread ids in Fig. 4) + - Consider the file `~/analyzer/src/analyses/threadFlag.ml` which implements a slightly more powerful version of the lightweight thread ids in Fig. 4 + - $\cal A$ is defined in `~/analyzer/src/cdomains/threadFlagDomain.ml` (Simple) + - The functions `threadenter` and `threadspawn` take care of computing appropriate successors + - ||^? is implemented in the function `may_race` + ~~~ocaml + let may_race (m1,b1) (m2,b2) = + let use_threadflag = GobConfig.get_bool "ana.race.digests.threadflag" in + let both_mt = Flag.is_multi m1 && Flag.is_multi m2 in + let one_not_main = Flag.is_not_main m1 || Flag.is_not_main m2 in + ((not use_threadflag) || (both_mt && one_not_main)) && b1 && b2 + ~~~ + - The `b` components concern interaction with other analysis and can be ignored for now + - After checking whether the digest should be used to exclude races `GobConfig.get_bool "ana.race.digests.threadflag"`, the predicate returns $\top$ (mapped to `true` here) if both accesses happen in multi-threaded mode, and at least one of the threads is not the unique main thread. + - The code in all the other digests is conceptually similar to the code provided here. + - Product of ||^? + - Consider `~/analyzer/src/analyses/mCPAccess.ml`, here the product construction happens + ~~~ocaml + let may_race x y = binop_for_all (fun n (module S: Analyses.MCPA) x y -> + S.may_race (Obj.obj x) (Obj.obj y) + ) x y + ~~~ + - Here a fold over two lists of digests (each corresponding to one activated digest) is performed to get the effect of the definition in Section 5.3) -**TODO** More recent versions of Goblint can be found at . @@ -131,7 +154,7 @@ To build Goblint from scratch, run `make release`. This artifact includes the benchmark programs on which we evaluated the verifiers. These benchmarks are taken from the publicly available sv-benchmarks set () -and correspond to the _ConcurrencySafety-Main_ category of SV-COMP'24 (). +and correspond to the _NoData-Race_ category of SV-COMP'25 (). The benchmarks are written in C and use POSIX threads (`pthreads`) to model concurrency. From 8efd3bb3b2bfcc144678db52d2156ef84d85c594 Mon Sep 17 00:00:00 2001 From: Michael Schwarz Date: Mon, 15 Sep 2025 17:22:55 +0800 Subject: [PATCH 58/68] Extending & Reusing --- README.md | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 526dc7bc1d..3969e8dd4e 100644 --- a/README.md +++ b/README.md @@ -160,12 +160,18 @@ The benchmarks are written in C and use POSIX threads (`pthreads`) to model conc ## Extending & Reusing This Artifact -* **Adding benchmarks:** You can easily add your own benchmarks programs written in C. **TODO!!!** - C programs should contain an empty function called `reach_error()`. Goblint and GemCutter then check that this function is never invoked. Certain (gcc) preprocessing steps may be necessary, e.g. to resolve `#include`s. See the SV-COMP benchmarks for examples (the preprocessed files typically have the extension `.i`). - - To run the evaluation on your own programs, you must edit the benchmark definition files `~/witness-generation/goblint.xml.template` resp. `~/witness-validation/gemcutter.xml.template`. - Replace the `` path specified in the task set `minimal` with your own path. - You can then simply run `~/scripts/quick-run.sh`. +* **Adding benchmarks:** You can easily add your own benchmarks programs written in C by following + the SV-COMP format and adding a task and corresponding *.yml file, e.g., to the folder `~/sv-benchmarks/c/pthread`. The easiest way to go about this is to copy the files `bigshot_p.*` and rename them to `yourtest.*`. + - The `*.c` file is provided for convenience only and contains the unpreprocessed program + - The `*.i` file contains the preprocessed (by GCC) program + - the `*.yml` file specifies: + - The input file (change to `yourtest.i`) + - The properties (of relevance here is only the `no-data-race.prp` property, change expected verdict according to your program) + - The memory model (change if you preprocessed for a 64bit machine) + + The framework automatically picks up new tasks placed in an existing directory. + +* **Adding your own analysis:** The easiest way to do this is to start with a simple analysis such as the thread-flag analysis described above and then gradually modifying it to obtain the desired analysis. ## Acknowledgment From 0466999b3e1b01bd81dff0e9687303309fb5e101 Mon Sep 17 00:00:00 2001 From: Michael Schwarz Date: Mon, 15 Sep 2025 17:25:07 +0800 Subject: [PATCH 59/68] Progress --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 3969e8dd4e..a4fe2fb7eb 100644 --- a/README.md +++ b/README.md @@ -62,10 +62,10 @@ You can also run the analysis for a subset of tasks and configurations by execut This evaluation supports all _experimental_ claims made in Section 7. Please note that Table 1 is not based on our experiments, but cited from the report on SV-COMP 2025. -All claims can be verified by opening the tables generated by the steps outlined in (4. Running the Full Experiments) which are located in **TODO**. -If results were only generated for some configs in that step, the remaining results can be verified using the tables located in **TODO** from our run inside the artifact. +- All claims can be verified by opening the tables generated by the steps outlined in (4. Running the Full Experiments) which are located in **TODO**. +- If results were only generated for some configs in that step, the remaining results can be verified using the tables located in `~/analyzer/results-our-artifact-run/results.*.table.html` where `*` is replaced with the date from our run inside the artifact. -These are HTML overviews as generated by the BenchExec benchmarking tool. +These are HTML overviews as generated by the BenchExec benchmarking tool, and can be opened by a browser. The table contains one configuration for every column of the table in Fig. 8 which are named by the activated digests. From 8871990d869a21e08ba76ce68d1f4c2411bef8d5 Mon Sep 17 00:00:00 2001 From: Michael Schwarz Date: Mon, 15 Sep 2025 17:32:22 +0800 Subject: [PATCH 60/68] Progress on reproduction --- README.md | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index a4fe2fb7eb..99ee1d8eac 100644 --- a/README.md +++ b/README.md @@ -96,14 +96,23 @@ Refers only to numbers in Fig. 8. The numbers in the VM are essentially the same as those on the server as Goblint is inherently single-threaded, and each of the cores of the server is not too powerful. Our run inside the VM matched exactly these numbers, however, some wiggle between machines is to be expected. +The numbers can be inspected by clicking on the `Table` tab on top of the document. +Then, change the dropdown for one of the configs from `Show all` to: +- Select `OUT OF MEMORY` to see how often Goblint ran out of memory +- Select `TIMEOUT` to see how often Goblint ran into a timeout +- Select `EXCEPTION(*)` to see the cases where Goblint crashed. > Where execution terminated, it did so within at most 20s, where for all but 6 tasks the runtime was below 10s. The same caveat as above applies here too. +The numbers can be inspected by clicking on the `Table` tab on top of the document. +Then, sort the runtime in a column by wall time by clicking on `walltime` twice. +In our run inside the artifact, there in fact were no tasks which ran more than `9s`, as each core in our machine for the VM is a bit more powerful than the cores in the server. Your run likely will not yield identical numbers, but they will be in the same ballpark. -The *Table* tab gives access to detailed evaluation results for each file. Clicking on a status shows the complete log for the benchmark run. + +The *Table* tab also gives access to detailed evaluation results for each file. Clicking on a status shows the complete log for the benchmark run. > **Note:** If you are trying to view logs for individual runs through the HTML table (by clicking on the evaluation result `true` or `false`), you may encounter a warning because browsers block access to local files. Follow the instructions in the message to enable log viewing. From 24aabcfa2559b3f3dbc34ff03331afb986c9fda7 Mon Sep 17 00:00:00 2001 From: Michael Schwarz Date: Mon, 15 Sep 2025 17:44:43 +0800 Subject: [PATCH 61/68] explanation --- README.md | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 99ee1d8eac..20021af397 100644 --- a/README.md +++ b/README.md @@ -51,11 +51,22 @@ The run should take no longer than 2 minutes, the expected output is Excellent: ignored check on tests/regression/03-practical/21-pfscan_combine_minimal.c:29 is now passing! No errors :) -You can also run the analysis for a subset of tasks and configurations by executing: +You can also run the analysis for a subset of tasks and configurations by executing from the analyzer directory: + benchexec ../benchexec/minimal.xml -o minimal_results +- This runs three configurations on 62 tasks and should run for no more than 2 minutes. +- Then, run the command output at the end (will look like `table-generator minimal_results/....`). +- Navigate to `minimal_results/results.*.table.html` (where `*` will be the timestamp when the command was run) and open the HTML file. +- The table will show `none` succeeding (`correct true`) for `1` task, `mute-only` for `14`, and +`full` for `41`. -### 4. Running the Full Experiments + + + + + +### 3. Running the Full Experiments ## Evaluation Results From 1ce8bf55e70a1f81f328ee69d1ed83e3c5b306dc Mon Sep 17 00:00:00 2001 From: Michael Schwarz Date: Mon, 15 Sep 2025 17:55:55 +0800 Subject: [PATCH 62/68] README --- README.md | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 20021af397..c7f77a9046 100644 --- a/README.md +++ b/README.md @@ -62,18 +62,23 @@ You can also run the analysis for a subset of tasks and configurations by execut `full` for `41`. +### 3. Running the Full Experiments +The full run of the experiments takes somewhere between 5 and 8 hours. If desired, this can be reduced by not evaluating all of the configurations, but only some of them (runtime is proportional to number of configurations). To disable configurations, comment them out in +`~/benchexec/races.xml`. +To run the experiments, from `~/analyzer` run + benechexec ../benchexec/races.xml -### 3. Running the Full Experiments +- Then, run the command output at the end (will look like `table-generator results/....`). ## Evaluation Results This evaluation supports all _experimental_ claims made in Section 7. Please note that Table 1 is not based on our experiments, but cited from the report on SV-COMP 2025. -- All claims can be verified by opening the tables generated by the steps outlined in (4. Running the Full Experiments) which are located in **TODO**. +- All claims can be verified by opening the tables generated by the steps outlined in (4. Running the Full Experiments) which are located in `~/analyzer/results/results.*.table.html`. - If results were only generated for some configs in that step, the remaining results can be verified using the tables located in `~/analyzer/results-our-artifact-run/results.*.table.html` where `*` is replaced with the date from our run inside the artifact. These are HTML overviews as generated by the BenchExec benchmarking tool, and can be opened by a browser. From 41a700c046963d7dd5faf8fa6cdb85810e8b98d2 Mon Sep 17 00:00:00 2001 From: Michael Schwarz Date: Tue, 16 Sep 2025 09:25:35 +0800 Subject: [PATCH 63/68] Remark on QWERTY keyboards --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index c7f77a9046..52a82d3a91 100644 --- a/README.md +++ b/README.md @@ -37,6 +37,8 @@ Follow these steps to set it up: You can then start the VM from the VirtualBox UI. Login with user `goblint` and password `goblint`. +The machine is configured for `QWERTY` keyboards by default. If you use a different layout, you can click the small `en` button on the top right of the screen to select you keyboard layout. + ### 2. Quick Test of the Benchmark Setup To check Goblint is properly installed, run From 6c7f9c937874a2d52320db4c581a5fce7053d03d Mon Sep 17 00:00:00 2001 From: Michael Schwarz Date: Tue, 16 Sep 2025 09:27:31 +0800 Subject: [PATCH 64/68] Relax timing constraints --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 52a82d3a91..9964c3d7c1 100644 --- a/README.md +++ b/README.md @@ -47,7 +47,7 @@ To check Goblint is properly installed, run make sanitytest on a console in the VM. -The run should take no longer than 2 minutes, the expected output is +The run should take no longer than 2-4 minutes, the expected output is Excellent: ignored check on tests/regression/03-practical/21-pfscan_combine_minimal.c:21 is now passing! Excellent: ignored check on tests/regression/03-practical/21-pfscan_combine_minimal.c:29 is now passing! @@ -57,7 +57,7 @@ You can also run the analysis for a subset of tasks and configurations by execut benchexec ../benchexec/minimal.xml -o minimal_results -- This runs three configurations on 62 tasks and should run for no more than 2 minutes. +- This runs three configurations on 62 tasks and should run for anywhere between 2 and 7 minutes (depending on your hardware). - Then, run the command output at the end (will look like `table-generator minimal_results/....`). - Navigate to `minimal_results/results.*.table.html` (where `*` will be the timestamp when the command was run) and open the HTML file. - The table will show `none` succeeding (`correct true`) for `1` task, `mute-only` for `14`, and From 47ce8faac03575ac93f315970c9149a7d4890f60 Mon Sep 17 00:00:00 2001 From: Michael Schwarz Date: Tue, 16 Sep 2025 09:31:07 +0800 Subject: [PATCH 65/68] Typo, commenting out --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 9964c3d7c1..503d0686f7 100644 --- a/README.md +++ b/README.md @@ -60,14 +60,14 @@ You can also run the analysis for a subset of tasks and configurations by execut - This runs three configurations on 62 tasks and should run for anywhere between 2 and 7 minutes (depending on your hardware). - Then, run the command output at the end (will look like `table-generator minimal_results/....`). - Navigate to `minimal_results/results.*.table.html` (where `*` will be the timestamp when the command was run) and open the HTML file. -- The table will show `none` succeeding (`correct true`) for `1` task, `mute-only` for `14`, and +- The table will show `none` succeeding (`correct true`) for `1` task, `mutex-only` for `14`, and `full` for `41`. ### 3. Running the Full Experiments -The full run of the experiments takes somewhere between 5 and 8 hours. If desired, this can be reduced by not evaluating all of the configurations, but only some of them (runtime is proportional to number of configurations). To disable configurations, comment them out in -`~/benchexec/races.xml`. +The full run of the experiments takes somewhere between 5 and 10 hours. If desired, this can be reduced by not evaluating all of the configurations, but only some of them (runtime is proportional to number of configurations). To disable configurations, you can remove them from +`~/benchexec/races.xml`, ideally after making a backup copy in case you decide to run some configuration after all. To run the experiments, from `~/analyzer` run From 5e79834a2ad3e21e52a1e8b8791f94fae0edebb5 Mon Sep 17 00:00:00 2001 From: Michael Schwarz Date: Tue, 16 Sep 2025 09:31:41 +0800 Subject: [PATCH 66/68] Typo --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 503d0686f7..d7963edf37 100644 --- a/README.md +++ b/README.md @@ -71,7 +71,7 @@ The full run of the experiments takes somewhere between 5 and 10 hours. If desir To run the experiments, from `~/analyzer` run - benechexec ../benchexec/races.xml + benchexec ../benchexec/races.xml - Then, run the command output at the end (will look like `table-generator results/....`). From 8383f03811b43b0c66b8fe9cbe98ad9fff84bc73 Mon Sep 17 00:00:00 2001 From: Michael Schwarz Date: Tue, 16 Sep 2025 09:42:10 +0800 Subject: [PATCH 67/68] Unzip necessary --- README.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index d7963edf37..6fc6d62f1e 100644 --- a/README.md +++ b/README.md @@ -80,7 +80,7 @@ To run the experiments, from `~/analyzer` run This evaluation supports all _experimental_ claims made in Section 7. Please note that Table 1 is not based on our experiments, but cited from the report on SV-COMP 2025. -- All claims can be verified by opening the tables generated by the steps outlined in (4. Running the Full Experiments) which are located in `~/analyzer/results/results.*.table.html`. +- All claims can be verified by opening the tables generated by the steps outlined in (3. Running the Full Experiments) which are located in `~/analyzer/results/results.*.table.html`. - If results were only generated for some configs in that step, the remaining results can be verified using the tables located in `~/analyzer/results-our-artifact-run/results.*.table.html` where `*` is replaced with the date from our run inside the artifact. These are HTML overviews as generated by the BenchExec benchmarking tool, and can be opened by a browser. @@ -130,7 +130,9 @@ In our run inside the artifact, there in fact were no tasks which ran more than -The *Table* tab also gives access to detailed evaluation results for each file. Clicking on a status shows the complete log for the benchmark run. +The *Table* tab also gives access to detailed evaluation results for each file. +For this to work, first unpack the `*.logfiles.zip` folder located in the `results` folder. +Clicking on a status then shows the complete log for the benchmark run. > **Note:** If you are trying to view logs for individual runs through the HTML table (by clicking on the evaluation result `true` or `false`), you may encounter a warning because browsers block access to local files. Follow the instructions in the message to enable log viewing. From e371abb87b645797e44c4a9d0011e8cb2b5cffe7 Mon Sep 17 00:00:00 2001 From: Michael Schwarz Date: Tue, 16 Sep 2025 09:47:24 +0800 Subject: [PATCH 68/68] License remark --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index 6fc6d62f1e..a730fb07e3 100644 --- a/README.md +++ b/README.md @@ -21,6 +21,10 @@ The next section gives instructions on how to setup and quickly get an overview The subsequent sections then describe each of these components in detail. The final section gives information on how to reuse this artifact. +Remark on license: + - `~/analyzer/LICENSE`: Is the MIT license governing the Goblint system as well as ancillary files such as this README + - The benchmarks from SV-COMP come with their individual licenses (all allowing for redistribution), where a `LICENSE` file is located in each folder of tasks or the license is otherwise directly recorded in the file header. + ## Getting Started