From dac7983d06e05f4180c7d53513d5b03cfe2d01b3 Mon Sep 17 00:00:00 2001 From: Michael Schwarz Date: Wed, 6 Sep 2023 10:05:31 +0200 Subject: [PATCH 001/140] Fix numbering --- .../{74-use_after_free => 78-use_after_free}/01-simple-uaf.c | 0 .../{74-use_after_free => 78-use_after_free}/02-conditional-uaf.c | 0 .../{74-use_after_free => 78-use_after_free}/03-nested-ptr-uaf.c | 0 .../04-function-call-uaf.c | 0 .../05-uaf-free-in-wrapper-fun.c | 0 .../{74-use_after_free => 78-use_after_free}/06-uaf-struct.c | 0 .../{74-use_after_free => 78-use_after_free}/07-itc-double-free.c | 0 .../08-itc-no-double-free.c | 0 .../{74-use_after_free => 78-use_after_free}/09-juliet-uaf.c | 0 .../10-juliet-double-free.c | 0 .../11-wrapper-funs-uaf.c | 0 .../12-multi-threaded-uaf.c | 0 .../13-multi-threaded-uaf-with-joined-thread.c | 0 13 files changed, 0 insertions(+), 0 deletions(-) rename tests/regression/{74-use_after_free => 78-use_after_free}/01-simple-uaf.c (100%) rename tests/regression/{74-use_after_free => 78-use_after_free}/02-conditional-uaf.c (100%) rename tests/regression/{74-use_after_free => 78-use_after_free}/03-nested-ptr-uaf.c (100%) rename tests/regression/{74-use_after_free => 78-use_after_free}/04-function-call-uaf.c (100%) rename tests/regression/{74-use_after_free => 78-use_after_free}/05-uaf-free-in-wrapper-fun.c (100%) rename tests/regression/{74-use_after_free => 78-use_after_free}/06-uaf-struct.c (100%) rename tests/regression/{74-use_after_free => 78-use_after_free}/07-itc-double-free.c (100%) rename tests/regression/{74-use_after_free => 78-use_after_free}/08-itc-no-double-free.c (100%) rename tests/regression/{74-use_after_free => 78-use_after_free}/09-juliet-uaf.c (100%) rename tests/regression/{74-use_after_free => 78-use_after_free}/10-juliet-double-free.c (100%) rename tests/regression/{74-use_after_free => 78-use_after_free}/11-wrapper-funs-uaf.c (100%) rename tests/regression/{74-use_after_free => 78-use_after_free}/12-multi-threaded-uaf.c (100%) rename tests/regression/{74-use_after_free => 78-use_after_free}/13-multi-threaded-uaf-with-joined-thread.c (100%) diff --git a/tests/regression/74-use_after_free/01-simple-uaf.c b/tests/regression/78-use_after_free/01-simple-uaf.c similarity index 100% rename from tests/regression/74-use_after_free/01-simple-uaf.c rename to tests/regression/78-use_after_free/01-simple-uaf.c diff --git a/tests/regression/74-use_after_free/02-conditional-uaf.c b/tests/regression/78-use_after_free/02-conditional-uaf.c similarity index 100% rename from tests/regression/74-use_after_free/02-conditional-uaf.c rename to tests/regression/78-use_after_free/02-conditional-uaf.c diff --git a/tests/regression/74-use_after_free/03-nested-ptr-uaf.c b/tests/regression/78-use_after_free/03-nested-ptr-uaf.c similarity index 100% rename from tests/regression/74-use_after_free/03-nested-ptr-uaf.c rename to tests/regression/78-use_after_free/03-nested-ptr-uaf.c diff --git a/tests/regression/74-use_after_free/04-function-call-uaf.c b/tests/regression/78-use_after_free/04-function-call-uaf.c similarity index 100% rename from tests/regression/74-use_after_free/04-function-call-uaf.c rename to tests/regression/78-use_after_free/04-function-call-uaf.c diff --git a/tests/regression/74-use_after_free/05-uaf-free-in-wrapper-fun.c b/tests/regression/78-use_after_free/05-uaf-free-in-wrapper-fun.c similarity index 100% rename from tests/regression/74-use_after_free/05-uaf-free-in-wrapper-fun.c rename to tests/regression/78-use_after_free/05-uaf-free-in-wrapper-fun.c diff --git a/tests/regression/74-use_after_free/06-uaf-struct.c b/tests/regression/78-use_after_free/06-uaf-struct.c similarity index 100% rename from tests/regression/74-use_after_free/06-uaf-struct.c rename to tests/regression/78-use_after_free/06-uaf-struct.c diff --git a/tests/regression/74-use_after_free/07-itc-double-free.c b/tests/regression/78-use_after_free/07-itc-double-free.c similarity index 100% rename from tests/regression/74-use_after_free/07-itc-double-free.c rename to tests/regression/78-use_after_free/07-itc-double-free.c diff --git a/tests/regression/74-use_after_free/08-itc-no-double-free.c b/tests/regression/78-use_after_free/08-itc-no-double-free.c similarity index 100% rename from tests/regression/74-use_after_free/08-itc-no-double-free.c rename to tests/regression/78-use_after_free/08-itc-no-double-free.c diff --git a/tests/regression/74-use_after_free/09-juliet-uaf.c b/tests/regression/78-use_after_free/09-juliet-uaf.c similarity index 100% rename from tests/regression/74-use_after_free/09-juliet-uaf.c rename to tests/regression/78-use_after_free/09-juliet-uaf.c diff --git a/tests/regression/74-use_after_free/10-juliet-double-free.c b/tests/regression/78-use_after_free/10-juliet-double-free.c similarity index 100% rename from tests/regression/74-use_after_free/10-juliet-double-free.c rename to tests/regression/78-use_after_free/10-juliet-double-free.c diff --git a/tests/regression/74-use_after_free/11-wrapper-funs-uaf.c b/tests/regression/78-use_after_free/11-wrapper-funs-uaf.c similarity index 100% rename from tests/regression/74-use_after_free/11-wrapper-funs-uaf.c rename to tests/regression/78-use_after_free/11-wrapper-funs-uaf.c diff --git a/tests/regression/74-use_after_free/12-multi-threaded-uaf.c b/tests/regression/78-use_after_free/12-multi-threaded-uaf.c similarity index 100% rename from tests/regression/74-use_after_free/12-multi-threaded-uaf.c rename to tests/regression/78-use_after_free/12-multi-threaded-uaf.c diff --git a/tests/regression/74-use_after_free/13-multi-threaded-uaf-with-joined-thread.c b/tests/regression/78-use_after_free/13-multi-threaded-uaf-with-joined-thread.c similarity index 100% rename from tests/regression/74-use_after_free/13-multi-threaded-uaf-with-joined-thread.c rename to tests/regression/78-use_after_free/13-multi-threaded-uaf-with-joined-thread.c From b3d9fe1ad02a2fd84455af118a3797922ba976d5 Mon Sep 17 00:00:00 2001 From: Stanimir Bozhilov Date: Wed, 6 Sep 2023 11:07:26 +0200 Subject: [PATCH 002/140] Set the global SV-COMP analysis state vars at all necessary places --- src/analyses/base.ml | 28 ++++++++++++++++++++-------- src/analyses/memLeak.ml | 12 +++++++++--- src/analyses/memOutOfBounds.ml | 5 ++++- 3 files changed, 33 insertions(+), 12 deletions(-) diff --git a/src/analyses/base.ml b/src/analyses/base.ml index f237ca8296..79ac13b861 100644 --- a/src/analyses/base.ml +++ b/src/analyses/base.ml @@ -1050,10 +1050,16 @@ struct | Mem n, ofs -> begin match (eval_rv a gs st n) with | Address adr -> - (if AD.is_null adr - then M.error ~category:M.Category.Behavior.Undefined.nullpointer_dereference ~tags:[CWE 476] "Must dereference NULL pointer" - else if AD.may_be_null adr - then M.warn ~category:M.Category.Behavior.Undefined.nullpointer_dereference ~tags:[CWE 476] "May dereference NULL pointer"); + ( + if AD.is_null adr then ( + AnalysisState.svcomp_may_invalid_deref := true; + M.error ~category:M.Category.Behavior.Undefined.nullpointer_dereference ~tags:[CWE 476] "Must dereference NULL pointer" + ) + else if AD.may_be_null adr then ( + AnalysisState.svcomp_may_invalid_deref := true; + M.warn ~category:M.Category.Behavior.Undefined.nullpointer_dereference ~tags:[CWE 476] "May dereference NULL pointer" + ) + ); AD.map (add_offset_varinfo (convert_offset a gs st ofs)) adr | _ -> M.debug ~category:Analyzer "Failed evaluating %a to lvalue" d_lval lval; @@ -2023,12 +2029,18 @@ struct match eval_rv_address (Analyses.ask_of_ctx ctx) ctx.global ctx.local ptr with | Address a -> let points_to_set = addrToLvalSet a in - if Q.LS.is_top points_to_set then - M.warn ~category:(Behavior (Undefined InvalidMemoryDeallocation)) ~tags:[CWE 590] "Points-to set for pointer %a in function %s is top. Potentially invalid memory deallocation may occur" d_exp ptr special_fn.vname - else if (Q.LS.exists (fun (v, _) -> not (ctx.ask (Q.IsHeapVar v))) points_to_set) || (AD.mem Addr.UnknownPtr a) then + if Q.LS.is_top points_to_set then ( + AnalysisState.svcomp_may_invalid_free := true; + M.warn ~category:(Behavior (Undefined InvalidMemoryDeallocation)) ~tags:[CWE 590; CWE 761] "Points-to set for pointer %a in function %s is top. Potentially invalid memory deallocation may occur" d_exp ptr special_fn.vname + ) + else if (Q.LS.exists (fun (v, _) -> not (ctx.ask (Q.IsHeapVar v))) points_to_set) || (AD.mem Addr.UnknownPtr a) then ( + AnalysisState.svcomp_may_invalid_free := true; M.warn ~category:(Behavior (Undefined InvalidMemoryDeallocation)) ~tags:[CWE 590] "Free of non-dynamically allocated memory in function %s for pointer %a" special_fn.vname d_exp ptr - else if Q.LS.exists (fun (_, o) -> Offset.Exp.cmp_zero_offset o <> `MustZero) points_to_set then + ) + else if Q.LS.exists (fun (_, o) -> Offset.Exp.cmp_zero_offset o <> `MustZero) points_to_set then ( + AnalysisState.svcomp_may_invalid_free := true; M.warn ~category:(Behavior (Undefined InvalidMemoryDeallocation)) ~tags:[CWE 761] "Free of memory not at start of buffer in function %s for pointer %a" special_fn.vname d_exp ptr + ) | _ -> M.warn ~category:MessageCategory.Analyzer "Pointer %a in function %s doesn't evaluate to a valid address." d_exp ptr special_fn.vname let special ctx (lv:lval option) (f: varinfo) (args: exp list) = diff --git a/src/analyses/memLeak.ml b/src/analyses/memLeak.ml index 99df5695a7..688ce1024a 100644 --- a/src/analyses/memLeak.ml +++ b/src/analyses/memLeak.ml @@ -19,15 +19,21 @@ struct (* HELPER FUNCTIONS *) let warn_for_multi_threaded ctx = - if not (ctx.ask (Queries.MustBeSingleThreaded { since_start = true })) then + if not (ctx.ask (Queries.MustBeSingleThreaded { since_start = true })) then ( + AnalysisState.svcomp_may_invalid_memtrack := true; M.warn ~category:(Behavior (Undefined MemoryLeak)) ~tags:[CWE 401] "Program isn't running in single-threaded mode. A memory leak might occur due to multi-threading" + ) let check_for_mem_leak ?(assert_exp_imprecise = false) ?(exp = None) ctx = let state = ctx.local in if not @@ D.is_empty state then match assert_exp_imprecise, exp with - | true, Some exp -> M.warn ~category:(Behavior (Undefined MemoryLeak)) ~tags:[CWE 401] "assert expression %a is unknown. Memory leak might possibly occur for heap variables: %a" d_exp exp D.pretty state - | _ -> M.warn ~category:(Behavior (Undefined MemoryLeak)) ~tags:[CWE 401] "Memory leak detected for heap variables: %a" D.pretty state + | true, Some exp -> + AnalysisState.svcomp_may_invalid_memtrack := true; + M.warn ~category:(Behavior (Undefined MemoryLeak)) ~tags:[CWE 401] "assert expression %a is unknown. Memory leak might possibly occur for heap variables: %a" d_exp exp D.pretty state + | _ -> + AnalysisState.svcomp_may_invalid_memtrack := true; + M.warn ~category:(Behavior (Undefined MemoryLeak)) ~tags:[CWE 401] "Memory leak detected for heap variables: %a" D.pretty state (* TRANSFER FUNCTIONS *) let return ctx (exp:exp option) (f:fundec) : D.t = diff --git a/src/analyses/memOutOfBounds.ml b/src/analyses/memOutOfBounds.ml index 0e93adb295..a7e95282fd 100644 --- a/src/analyses/memOutOfBounds.ml +++ b/src/analyses/memOutOfBounds.ml @@ -194,7 +194,10 @@ struct IntDomain.IntDomTuple.top_of @@ Cilfacade.ptrdiff_ikind () end | _ -> - M.warn "Pointer %a has a points-to-set of top. An invalid memory access might occur" d_exp ptr; + ( + AnalysisState.svcomp_may_invalid_deref :=true; + M.warn "Pointer %a has a points-to-set of top. An invalid memory access might occur" d_exp ptr + ); IntDomain.IntDomTuple.top_of @@ Cilfacade.ptrdiff_ikind () and check_lval_for_oob_access ctx ?(is_implicitly_derefed = false) lval = From 46ae6ee1d5bfacbed5ced3b475249d724d540601 Mon Sep 17 00:00:00 2001 From: Stanimir Bozhilov Date: Wed, 6 Sep 2023 16:43:53 +0200 Subject: [PATCH 003/140] Add extra parentheses in witness.ml for memory safety result generation --- src/witness/witness.ml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/witness/witness.ml b/src/witness/witness.ml index 264e0bc066..31034a2d9a 100644 --- a/src/witness/witness.ml +++ b/src/witness/witness.ml @@ -512,7 +512,7 @@ struct let next _ = [] end in - if not !AnalysisState.svcomp_may_invalid_free then + if not !AnalysisState.svcomp_may_invalid_free then ( let module TaskResult = struct module Arg = Arg @@ -523,7 +523,7 @@ struct end in (module TaskResult:WitnessTaskResult) - else ( + ) else ( let module TaskResult = struct module Arg = TrivialArg @@ -542,7 +542,7 @@ struct let next _ = [] end in - if not !AnalysisState.svcomp_may_invalid_deref then + if not !AnalysisState.svcomp_may_invalid_deref then ( let module TaskResult = struct module Arg = Arg @@ -553,7 +553,7 @@ struct end in (module TaskResult:WitnessTaskResult) - else ( + ) else ( let module TaskResult = struct module Arg = TrivialArg @@ -572,7 +572,7 @@ struct let next _ = [] end in - if not !AnalysisState.svcomp_may_invalid_memtrack then + if not !AnalysisState.svcomp_may_invalid_memtrack then ( let module TaskResult = struct module Arg = Arg @@ -583,7 +583,7 @@ struct end in (module TaskResult:WitnessTaskResult) - else ( + ) else ( let module TaskResult = struct module Arg = TrivialArg From d4ef55594e2f388febfb31e598e47691b7dafc90 Mon Sep 17 00:00:00 2001 From: Stanimir Bozhilov Date: Wed, 6 Sep 2023 17:21:58 +0200 Subject: [PATCH 004/140] Add quick and dirty workaround attempt for working with SV-COMP's memory-safety category --- src/autoTune.ml | 1 + src/witness/svcomp.ml | 1 + src/witness/svcompSpec.ml | 14 ++++++++---- src/witness/witness.ml | 46 ++++++++++++++++++++++++++++++++------- 4 files changed, 50 insertions(+), 12 deletions(-) diff --git a/src/autoTune.ml b/src/autoTune.ml index d532081799..9e3508ccd2 100644 --- a/src/autoTune.ml +++ b/src/autoTune.ml @@ -226,6 +226,7 @@ let focusOnSpecification () = (* TODO: Finish these two below later *) | ValidDeref | ValidMemtrack -> () + | MemorySafety -> () (* TODO: This is here for now just to complete the pattern match *) (*Detect enumerations and enable the "ana.int.enums" option*) exception EnumFound diff --git a/src/witness/svcomp.ml b/src/witness/svcomp.ml index f1ee18ed72..15d41c0210 100644 --- a/src/witness/svcomp.ml +++ b/src/witness/svcomp.ml @@ -55,6 +55,7 @@ struct | ValidFree -> "valid-free" | ValidDeref -> "valid-deref" | ValidMemtrack -> "valid-memtrack" + | MemorySafety -> "memory-safety" (* TODO: Currently here only to complete the pattern match *) in "false(" ^ result_spec ^ ")" | Unknown -> "unknown" diff --git a/src/witness/svcompSpec.ml b/src/witness/svcompSpec.ml index 8dafb8873c..f066610953 100644 --- a/src/witness/svcompSpec.ml +++ b/src/witness/svcompSpec.ml @@ -9,10 +9,11 @@ type t = | ValidFree | ValidDeref | ValidMemtrack + | MemorySafety (* Internal property for use in Goblint; serves as a summary for ValidFree, ValidDeref and ValidMemtrack *) let of_string s = let s = String.strip s in - let regexp = Str.regexp "CHECK( init(main()), LTL(G \\(.*\\)) )" in + let regexp = Str.regexp "CHECK( init(main()), LTL(G \\(.*\\)) )\nCHECK( init(main()), LTL(G \\(.*\\)) )\nCHECK( init(main()), LTL(G \\(.*\\)) )" in let regexp_negated = Str.regexp "CHECK( init(main()), LTL(G ! \\(.*\\)) )" in if Str.string_match regexp_negated s 0 then let global_not = Str.matched_group 1 s in @@ -28,13 +29,17 @@ let of_string s = else failwith "Svcomp.Specification.of_string: unknown global not expression" else if Str.string_match regexp s 0 then - let global = Str.matched_group 1 s in - if global = "valid-free" then + let global1 = Str.matched_group 1 s in + let global2 = Str.matched_group 2 s in + let global3 = Str.matched_group 3 s in + if global1 = "valid-free" && global2 = "valid-deref" && global3 = "valid-memtrack" then + MemorySafety + (* if global = "valid-free" then ValidFree else if global = "valid-deref" then ValidDeref else if global = "valid-memtrack" then - ValidMemtrack + ValidMemtrack *) else failwith "Svcomp.Specification.of_string: unknown global expression" else @@ -65,5 +70,6 @@ let to_string spec = | ValidFree -> "valid-free", false | ValidDeref -> "valid-deref", false | ValidMemtrack -> "valid-memtrack", false + | MemorySafety -> "memory-safety", false (* TODO: That's false, it's currently here just to complete the pattern match *) in print_output spec_str is_neg diff --git a/src/witness/witness.ml b/src/witness/witness.ml index 31034a2d9a..437ba187ae 100644 --- a/src/witness/witness.ml +++ b/src/witness/witness.ml @@ -505,8 +505,8 @@ struct in (module TaskResult:WitnessTaskResult) ) - | ValidFree -> - let module TrivialArg = + | ValidFree (*->*) + (* let module TrivialArg = struct include Arg let next _ = [] @@ -534,9 +534,9 @@ struct end in (module TaskResult:WitnessTaskResult) - ) - | ValidDeref -> - let module TrivialArg = + ) *) + | ValidDeref (*->*) + (* let module TrivialArg = struct include Arg let next _ = [] @@ -564,9 +564,9 @@ struct end in (module TaskResult:WitnessTaskResult) - ) - | ValidMemtrack -> - let module TrivialArg = + ) *) + | ValidMemtrack (*->*) + (* let module TrivialArg = struct include Arg let next _ = [] @@ -583,6 +583,36 @@ struct end in (module TaskResult:WitnessTaskResult) + ) else ( + let module TaskResult = + struct + module Arg = TrivialArg + let result = Result.Unknown + let invariant _ = Invariant.none + let is_violation _ = false + let is_sink _ = false + end + in + (module TaskResult:WitnessTaskResult) + ) *) + | MemorySafety -> + let module TrivialArg = + struct + include Arg + let next _ = [] + end + in + if not !AnalysisState.svcomp_may_invalid_free || not !AnalysisState.svcomp_may_invalid_deref || not !AnalysisState.svcomp_may_invalid_memtrack then ( + let module TaskResult = + struct + module Arg = Arg + let result = Result.True + let invariant _ = Invariant.none + let is_violation _ = false + let is_sink _ = false + end + in + (module TaskResult:WitnessTaskResult) ) else ( let module TaskResult = struct From 2fb4d743374fd4322ad2fa2ce98bcaf91d8870ee Mon Sep 17 00:00:00 2001 From: Stanimir Bozhilov Date: Wed, 6 Sep 2023 18:59:51 +0200 Subject: [PATCH 005/140] Use logical AND and not OR for the memory-safety category in witness --- src/witness/witness.ml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/witness/witness.ml b/src/witness/witness.ml index 437ba187ae..66a62d1b03 100644 --- a/src/witness/witness.ml +++ b/src/witness/witness.ml @@ -602,7 +602,7 @@ struct let next _ = [] end in - if not !AnalysisState.svcomp_may_invalid_free || not !AnalysisState.svcomp_may_invalid_deref || not !AnalysisState.svcomp_may_invalid_memtrack then ( + if not !AnalysisState.svcomp_may_invalid_free && not !AnalysisState.svcomp_may_invalid_deref && not !AnalysisState.svcomp_may_invalid_memtrack then ( let module TaskResult = struct module Arg = Arg From 9cbf2ab8d10c064a1c1714e700b3b405478b81ae Mon Sep 17 00:00:00 2001 From: Stanimir Bozhilov Date: Sat, 9 Sep 2023 23:13:03 +0200 Subject: [PATCH 006/140] Add util function for setting mem safety global vars Make sure to do this only if we're in postsolving --- src/analyses/base.ml | 10 +++++----- src/analyses/memLeak.ml | 7 ++++--- src/analyses/memOutOfBounds.ml | 13 +++++++------ src/analyses/useAfterFree.ml | 17 ++++++----------- src/util/analysisStateUtil.ml | 11 +++++++++++ 5 files changed, 33 insertions(+), 25 deletions(-) create mode 100644 src/util/analysisStateUtil.ml diff --git a/src/analyses/base.ml b/src/analyses/base.ml index 79ac13b861..0cdcf98fc0 100644 --- a/src/analyses/base.ml +++ b/src/analyses/base.ml @@ -1052,11 +1052,11 @@ struct | Address adr -> ( if AD.is_null adr then ( - AnalysisState.svcomp_may_invalid_deref := true; + AnalysisStateUtil.set_mem_safety_flag InvalidDeref; M.error ~category:M.Category.Behavior.Undefined.nullpointer_dereference ~tags:[CWE 476] "Must dereference NULL pointer" ) else if AD.may_be_null adr then ( - AnalysisState.svcomp_may_invalid_deref := true; + AnalysisStateUtil.set_mem_safety_flag InvalidDeref; M.warn ~category:M.Category.Behavior.Undefined.nullpointer_dereference ~tags:[CWE 476] "May dereference NULL pointer" ) ); @@ -2030,15 +2030,15 @@ struct | Address a -> let points_to_set = addrToLvalSet a in if Q.LS.is_top points_to_set then ( - AnalysisState.svcomp_may_invalid_free := true; + AnalysisStateUtil.set_mem_safety_flag InvalidFree; M.warn ~category:(Behavior (Undefined InvalidMemoryDeallocation)) ~tags:[CWE 590; CWE 761] "Points-to set for pointer %a in function %s is top. Potentially invalid memory deallocation may occur" d_exp ptr special_fn.vname ) else if (Q.LS.exists (fun (v, _) -> not (ctx.ask (Q.IsHeapVar v))) points_to_set) || (AD.mem Addr.UnknownPtr a) then ( - AnalysisState.svcomp_may_invalid_free := true; + AnalysisStateUtil.set_mem_safety_flag InvalidFree; M.warn ~category:(Behavior (Undefined InvalidMemoryDeallocation)) ~tags:[CWE 590] "Free of non-dynamically allocated memory in function %s for pointer %a" special_fn.vname d_exp ptr ) else if Q.LS.exists (fun (_, o) -> Offset.Exp.cmp_zero_offset o <> `MustZero) points_to_set then ( - AnalysisState.svcomp_may_invalid_free := true; + AnalysisStateUtil.set_mem_safety_flag InvalidFree; M.warn ~category:(Behavior (Undefined InvalidMemoryDeallocation)) ~tags:[CWE 761] "Free of memory not at start of buffer in function %s for pointer %a" special_fn.vname d_exp ptr ) | _ -> M.warn ~category:MessageCategory.Analyzer "Pointer %a in function %s doesn't evaluate to a valid address." d_exp ptr special_fn.vname diff --git a/src/analyses/memLeak.ml b/src/analyses/memLeak.ml index 688ce1024a..0ea4fc96b1 100644 --- a/src/analyses/memLeak.ml +++ b/src/analyses/memLeak.ml @@ -3,6 +3,7 @@ open GoblintCil open Analyses open MessageCategory +open AnalysisStateUtil module ToppedVarInfoSet = SetDomain.ToppedSet(CilType.Varinfo)(struct let topname = "All Heap Variables" end) @@ -20,7 +21,7 @@ struct (* HELPER FUNCTIONS *) let warn_for_multi_threaded ctx = if not (ctx.ask (Queries.MustBeSingleThreaded { since_start = true })) then ( - AnalysisState.svcomp_may_invalid_memtrack := true; + set_mem_safety_flag InvalidMemTrack; M.warn ~category:(Behavior (Undefined MemoryLeak)) ~tags:[CWE 401] "Program isn't running in single-threaded mode. A memory leak might occur due to multi-threading" ) @@ -29,10 +30,10 @@ struct if not @@ D.is_empty state then match assert_exp_imprecise, exp with | true, Some exp -> - AnalysisState.svcomp_may_invalid_memtrack := true; + AnalysisStateUtil.set_mem_safety_flag InvalidMemTrack; M.warn ~category:(Behavior (Undefined MemoryLeak)) ~tags:[CWE 401] "assert expression %a is unknown. Memory leak might possibly occur for heap variables: %a" d_exp exp D.pretty state | _ -> - AnalysisState.svcomp_may_invalid_memtrack := true; + AnalysisStateUtil.set_mem_safety_flag InvalidMemTrack; M.warn ~category:(Behavior (Undefined MemoryLeak)) ~tags:[CWE 401] "Memory leak detected for heap variables: %a" D.pretty state (* TRANSFER FUNCTIONS *) diff --git a/src/analyses/memOutOfBounds.ml b/src/analyses/memOutOfBounds.ml index a7e95282fd..a5cf7d2ca2 100644 --- a/src/analyses/memOutOfBounds.ml +++ b/src/analyses/memOutOfBounds.ml @@ -1,6 +1,7 @@ open GoblintCil open Analyses open MessageCategory +open AnalysisStateUtil module AS = AnalysisState module VDQ = ValueDomainQueries @@ -195,7 +196,7 @@ struct end | _ -> ( - AnalysisState.svcomp_may_invalid_deref :=true; + set_mem_safety_flag InvalidDeref; M.warn "Pointer %a has a points-to-set of top. An invalid memory access might occur" d_exp ptr ); IntDomain.IntDomTuple.top_of @@ Cilfacade.ptrdiff_ikind () @@ -229,12 +230,12 @@ struct | Some t -> begin match VDQ.ID.is_top ptr_size with | true -> - AS.svcomp_may_invalid_deref := true; + set_mem_safety_flag InvalidDeref; M.warn ~category:(Behavior behavior) ~tags:[CWE cwe_number] "Size of pointer %a not known. Memory out-of-bounds access might occur due to pointer arithmetic" d_exp lval_exp | false -> let offs = `Lifted addr_offs in if ptr_size < offs then begin - AS.svcomp_may_invalid_deref := true; + set_mem_safety_flag InvalidDeref; M.warn ~category:(Behavior behavior) ~tags:[CWE cwe_number] "Size of pointer is %a (in bytes). It is offset by %a (in bytes) due to pointer arithmetic. Memory out-of-bounds access must occur" VDQ.ID.pretty ptr_size VDQ.ID.pretty offs end end @@ -287,14 +288,14 @@ struct in begin match VDQ.ID.is_top ptr_size, VDQ.ID.is_top offset_size_with_addr_size with | true, _ -> - AS.svcomp_may_invalid_deref := true; + set_mem_safety_flag InvalidDeref; M.warn ~category:(Behavior behavior) ~tags:[CWE cwe_number] "Size of pointer %a in expression %a not known. Memory out-of-bounds access might occur" d_exp e1 d_exp binopexp | _, true -> - AS.svcomp_may_invalid_deref := true; + set_mem_safety_flag InvalidDeref; M.warn ~category:(Behavior behavior) ~tags:[CWE cwe_number] "Operand value for pointer arithmetic in expression %a not known. Memory out-of-bounds access might occur" d_exp binopexp | false, false -> if ptr_size < offset_size_with_addr_size then begin - AS.svcomp_may_invalid_deref := true; + set_mem_safety_flag InvalidDeref; M.warn ~category:(Behavior behavior) ~tags:[CWE cwe_number] "Size of pointer in expression %a is %a (in bytes). It is offset by %a (in bytes). Memory out-of-bounds access must occur" d_exp binopexp VDQ.ID.pretty ptr_size VDQ.ID.pretty offset_size_with_addr_size end end diff --git a/src/analyses/useAfterFree.ml b/src/analyses/useAfterFree.ml index 9af1b8ca7a..9dac016ce5 100644 --- a/src/analyses/useAfterFree.ml +++ b/src/analyses/useAfterFree.ml @@ -3,6 +3,7 @@ open GoblintCil open Analyses open MessageCategory +open AnalysisStateUtil module ToppedVarInfoSet = SetDomain.ToppedSet(CilType.Varinfo)(struct let topname = "All Heap Variables" end) module ThreadIdToJoinedThreadsMap = MapDomain.MapBot(ThreadIdDomain.ThreadLifted)(ConcDomain.MustThreadSet) @@ -24,12 +25,6 @@ struct (* HELPER FUNCTIONS *) - let set_global_svcomp_var is_double_free = - if is_double_free then - AnalysisState.svcomp_may_invalid_free := true - else - AnalysisState.svcomp_may_invalid_deref := true - let get_current_threadid ctx = ctx.ask Queries.CurrentThreadId @@ -65,23 +60,23 @@ struct | `Lifted current -> let possibly_started = G.exists (possibly_started current) freeing_threads in if possibly_started then begin - set_global_svcomp_var is_double_free; + if is_double_free then set_mem_safety_flag InvalidFree else set_mem_safety_flag InvalidDeref; M.warn ~category:(Behavior behavior) ~tags:[CWE cwe_number] "There's a thread that's been started in parallel with the memory-freeing threads for heap variable %a. %s might occur" CilType.Varinfo.pretty heap_var bug_name end else begin let current_is_unique = ThreadId.Thread.is_unique current in let any_equal_current threads = G.exists (equal_current current) threads in if not current_is_unique && any_equal_current freeing_threads then begin - set_global_svcomp_var is_double_free; + if is_double_free then set_mem_safety_flag InvalidFree else set_mem_safety_flag InvalidDeref; M.warn ~category:(Behavior behavior) ~tags:[CWE cwe_number] "Current thread is not unique and a %s might occur for heap variable %a" bug_name CilType.Varinfo.pretty heap_var end else if D.mem heap_var ctx.local then begin - set_global_svcomp_var is_double_free; + if is_double_free then set_mem_safety_flag InvalidFree else set_mem_safety_flag InvalidDeref; M.warn ~category:(Behavior behavior) ~tags:[CWE cwe_number] "%s might occur in current unique thread %a for heap variable %a" bug_name ThreadIdDomain.FlagConfiguredTID.pretty current CilType.Varinfo.pretty heap_var end end | `Top -> - set_global_svcomp_var is_double_free; + if is_double_free then set_mem_safety_flag InvalidFree else set_mem_safety_flag InvalidDeref; M.warn ~category:(Behavior behavior) ~tags:[CWE cwe_number] "CurrentThreadId is top. %s might occur for heap variable %a" bug_name CilType.Varinfo.pretty heap_var | `Bot -> M.warn ~category:MessageCategory.Analyzer "CurrentThreadId is bottom" @@ -110,7 +105,7 @@ struct | a when not (Queries.LS.is_top a) && not (Queries.LS.mem (dummyFunDec.svar, `NoOffset) a) -> let warn_for_heap_var var = if D.mem var state then begin - set_global_svcomp_var is_double_free; + if is_double_free then set_mem_safety_flag InvalidFree else set_mem_safety_flag InvalidDeref; M.warn ~category:(Behavior undefined_behavior) ~tags:[CWE cwe_number] "lval (%s) in \"%s\" points to a maybe freed memory region" var.vname transfer_fn_name end in diff --git a/src/util/analysisStateUtil.ml b/src/util/analysisStateUtil.ml new file mode 100644 index 0000000000..25914f8c8e --- /dev/null +++ b/src/util/analysisStateUtil.ml @@ -0,0 +1,11 @@ +type mem_safety_violation = + | InvalidFree + | InvalidDeref + | InvalidMemTrack + +let set_mem_safety_flag violation_type = + if !AnalysisState.postsolving then + match violation_type with + | InvalidFree -> AnalysisState.svcomp_may_invalid_free := true + | InvalidDeref -> AnalysisState.svcomp_may_invalid_deref := true + | InvalidMemTrack -> AnalysisState.svcomp_may_invalid_memtrack := true \ No newline at end of file From 3258cce90b88ea14db99c5e6466b43b7fd8a01a5 Mon Sep 17 00:00:00 2001 From: Stanimir Bozhilov Date: Sat, 9 Sep 2023 23:35:54 +0200 Subject: [PATCH 007/140] Don't warn for pointers that only contain strings in their pts --- src/analyses/memOutOfBounds.ml | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/analyses/memOutOfBounds.ml b/src/analyses/memOutOfBounds.ml index a5cf7d2ca2..4c2576ec24 100644 --- a/src/analyses/memOutOfBounds.ml +++ b/src/analyses/memOutOfBounds.ml @@ -161,6 +161,13 @@ struct let remaining_offset = offs_to_idx typ o in IntDomain.IntDomTuple.add bytes_offset remaining_offset + let ptr_only_has_str_addr ctx ptr = + ctx.ask (Queries.MayPointTo ptr) + |> VDQ.LS.elements + |> List.map (fun (v, o) -> ValueDomain.Addr.of_mval (v, ValueDomain.Addr.Offs.of_exp o)) + |> ValueDomain.AD.of_list + |> ValueDomain.AD.for_all (fun addr -> match addr with | StrPtr _ -> true | _ -> false) + let rec get_addr_offs ctx ptr = match ctx.ask (Queries.MayPointTo ptr) with | a when not (VDQ.LS.is_top a) -> @@ -202,7 +209,8 @@ struct IntDomain.IntDomTuple.top_of @@ Cilfacade.ptrdiff_ikind () and check_lval_for_oob_access ctx ?(is_implicitly_derefed = false) lval = - if not @@ lval_contains_a_ptr lval then () + (* If the lval does not contain a pointer or if it does contain a pointer, but only points to string addresses, then no need to WARN *) + if (not @@ lval_contains_a_ptr lval) || ptr_only_has_str_addr ctx (Lval lval) then () else (* If the lval doesn't indicate an explicit dereference, we still need to check for an implicit dereference *) (* An implicit dereference is, e.g., printf("%p", ptr), where ptr is a pointer *) From 0881fb786b7a4a17c0fd5adadc50378580c99a73 Mon Sep 17 00:00:00 2001 From: Stanimir Bozhilov Date: Sat, 9 Sep 2023 23:39:05 +0200 Subject: [PATCH 008/140] Set global mem safety flags upon array oob as well --- src/cdomains/arrayDomain.ml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/cdomains/arrayDomain.ml b/src/cdomains/arrayDomain.ml index c099a94f96..2f91e47663 100644 --- a/src/cdomains/arrayDomain.ml +++ b/src/cdomains/arrayDomain.ml @@ -787,14 +787,19 @@ let array_oob_check ( type a ) (module Idx: IntDomain.Z with type t = a) (x, l) | Some true, Some true -> (* Certainly in bounds on both sides.*) () | Some true, Some false -> (* The following matching differentiates the must and may cases*) + AnalysisStateUtil.set_mem_safety_flag InvalidDeref; M.error ~category:M.Category.Behavior.Undefined.ArrayOutOfBounds.past_end "Must access array past end" | Some true, None -> + AnalysisStateUtil.set_mem_safety_flag InvalidDeref; M.warn ~category:M.Category.Behavior.Undefined.ArrayOutOfBounds.past_end "May access array past end" | Some false, Some true -> + AnalysisStateUtil.set_mem_safety_flag InvalidDeref; M.error ~category:M.Category.Behavior.Undefined.ArrayOutOfBounds.before_start "Must access array before start" | None, Some true -> + AnalysisStateUtil.set_mem_safety_flag InvalidDeref; M.warn ~category:M.Category.Behavior.Undefined.ArrayOutOfBounds.before_start "May access array before start" | _ -> + AnalysisStateUtil.set_mem_safety_flag InvalidDeref; M.warn ~category:M.Category.Behavior.Undefined.ArrayOutOfBounds.unknown "May access array out of bounds" else () From b9faa8f039a6ad5faeb2ea16483c9c1b179b71da Mon Sep 17 00:00:00 2001 From: Stanimir Bozhilov Date: Sat, 9 Sep 2023 23:47:58 +0200 Subject: [PATCH 009/140] Cast pointer arithmetic offsets without using Option.get --- src/analyses/memOutOfBounds.ml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/analyses/memOutOfBounds.ml b/src/analyses/memOutOfBounds.ml index 4c2576ec24..a2c180a453 100644 --- a/src/analyses/memOutOfBounds.ml +++ b/src/analyses/memOutOfBounds.ml @@ -138,11 +138,12 @@ struct let eval_ptr_offset_in_binop ctx exp ptr_contents_typ = let eval_offset = ctx.ask (Queries.EvalInt exp) in - let eval_offset = Option.get @@ VDQ.ID.to_int eval_offset in - let eval_offset = VDQ.ID.of_int (Cilfacade.ptrdiff_ikind ()) eval_offset in let ptr_contents_typ_size_in_bytes = size_of_type_in_bytes ptr_contents_typ in match eval_offset with - | `Lifted i -> `Lifted (IntDomain.IntDomTuple.mul i ptr_contents_typ_size_in_bytes) + | `Lifted i -> + (* The offset must be casted to ptrdiff_ikind in order to have matching ikinds for the multiplication below *) + let casted_offset = IntDomain.IntDomTuple.cast_to (Cilfacade.ptrdiff_ikind ()) i in + `Lifted (IntDomain.IntDomTuple.mul casted_offset ptr_contents_typ_size_in_bytes) | `Top -> `Top | `Bot -> `Bot From 8a6cf0a10258cd6c433f6067111b10f93323002d Mon Sep 17 00:00:00 2001 From: Stanimir Bozhilov Date: Sun, 10 Sep 2023 02:11:41 +0200 Subject: [PATCH 010/140] Check and warn everywhere for a top points-to set in memOutOfBounds --- src/analyses/memOutOfBounds.ml | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/src/analyses/memOutOfBounds.ml b/src/analyses/memOutOfBounds.ml index a2c180a453..781c48d8e9 100644 --- a/src/analyses/memOutOfBounds.ml +++ b/src/analyses/memOutOfBounds.ml @@ -88,7 +88,9 @@ struct match ctx.ask (Queries.MayPointTo ptr) with | a when not (Queries.LS.is_top a) && not (Queries.LS.mem (dummyFunDec.svar, `NoOffset) a) -> Queries.LS.for_all (fun (v, _) -> ctx.ask (Queries.IsHeapVar v)) a - | _ -> false + | _ -> + M.warn "Pointer %a has a points-to set of top. An invalid memory access might occur" d_exp ptr; + false let get_size_of_ptr_target ctx ptr = if points_to_heap_only ctx ptr then @@ -124,7 +126,7 @@ struct ) x xs end | _ -> - M.warn "Pointer %a has a points-to-set of top. An invalid memory access might occur" d_exp ptr; + M.warn "Pointer %a has a points-to set of top. An invalid memory access might occur" d_exp ptr; VDQ.ID.top () let get_ptr_deref_type ptr_typ = @@ -163,11 +165,16 @@ struct IntDomain.IntDomTuple.add bytes_offset remaining_offset let ptr_only_has_str_addr ctx ptr = - ctx.ask (Queries.MayPointTo ptr) - |> VDQ.LS.elements - |> List.map (fun (v, o) -> ValueDomain.Addr.of_mval (v, ValueDomain.Addr.Offs.of_exp o)) - |> ValueDomain.AD.of_list - |> ValueDomain.AD.for_all (fun addr -> match addr with | StrPtr _ -> true | _ -> false) + match ctx.ask (Queries.MayPointTo ptr) with + | a when not (VDQ.LS.is_top a) -> + VDQ.LS.elements a + |> List.map (fun (v, o) -> ValueDomain.Addr.of_mval (v, ValueDomain.Addr.Offs.of_exp o)) + |> ValueDomain.AD.of_list + |> ValueDomain.AD.for_all (fun addr -> match addr with | StrPtr _ -> true | _ -> false) + | _ -> + M.warn "Pointer %a has a points-to set of top. An invalid memory access might occur" d_exp ptr; + (* Intuition: if the points-to set is top, then we don't know with certainty if there are only string addresses inside *) + false let rec get_addr_offs ctx ptr = match ctx.ask (Queries.MayPointTo ptr) with @@ -203,10 +210,8 @@ struct IntDomain.IntDomTuple.top_of @@ Cilfacade.ptrdiff_ikind () end | _ -> - ( - set_mem_safety_flag InvalidDeref; - M.warn "Pointer %a has a points-to-set of top. An invalid memory access might occur" d_exp ptr - ); + set_mem_safety_flag InvalidDeref; + M.warn "Pointer %a has a points-to set of top. An invalid memory access might occur" d_exp ptr; IntDomain.IntDomTuple.top_of @@ Cilfacade.ptrdiff_ikind () and check_lval_for_oob_access ctx ?(is_implicitly_derefed = false) lval = From 29f13a281aa183722b375c163d427c434d70dcbd Mon Sep 17 00:00:00 2001 From: Stanimir Bozhilov Date: Sun, 10 Sep 2023 14:06:34 +0200 Subject: [PATCH 011/140] Simplify string address check and remove extra warning --- src/analyses/memOutOfBounds.ml | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/src/analyses/memOutOfBounds.ml b/src/analyses/memOutOfBounds.ml index 781c48d8e9..de18021278 100644 --- a/src/analyses/memOutOfBounds.ml +++ b/src/analyses/memOutOfBounds.ml @@ -88,9 +88,7 @@ struct match ctx.ask (Queries.MayPointTo ptr) with | a when not (Queries.LS.is_top a) && not (Queries.LS.mem (dummyFunDec.svar, `NoOffset) a) -> Queries.LS.for_all (fun (v, _) -> ctx.ask (Queries.IsHeapVar v)) a - | _ -> - M.warn "Pointer %a has a points-to set of top. An invalid memory access might occur" d_exp ptr; - false + | _ -> false let get_size_of_ptr_target ctx ptr = if points_to_heap_only ctx ptr then @@ -165,16 +163,14 @@ struct IntDomain.IntDomTuple.add bytes_offset remaining_offset let ptr_only_has_str_addr ctx ptr = - match ctx.ask (Queries.MayPointTo ptr) with - | a when not (VDQ.LS.is_top a) -> - VDQ.LS.elements a - |> List.map (fun (v, o) -> ValueDomain.Addr.of_mval (v, ValueDomain.Addr.Offs.of_exp o)) - |> ValueDomain.AD.of_list - |> ValueDomain.AD.for_all (fun addr -> match addr with | StrPtr _ -> true | _ -> false) - | _ -> - M.warn "Pointer %a has a points-to set of top. An invalid memory access might occur" d_exp ptr; - (* Intuition: if the points-to set is top, then we don't know with certainty if there are only string addresses inside *) - false + match ctx.ask (Queries.EvalValue ptr) with + | a when not (Queries.VD.is_top a) -> + begin match a with + | Address a -> ValueDomain.AD.for_all (fun addr -> match addr with | StrPtr _ -> true | _ -> false) a + | _ -> false + end + (* Intuition: if ptr evaluates to top, it could all sorts of things and not only string addresses *) + | _ -> false let rec get_addr_offs ctx ptr = match ctx.ask (Queries.MayPointTo ptr) with From 7bdce29722c52c4366f0ff7457ad2b6c12f2ebeb Mon Sep 17 00:00:00 2001 From: Stanimir Bozhilov Date: Sun, 10 Sep 2023 14:17:25 +0200 Subject: [PATCH 012/140] Add check for dereferencing a pointer containing an unknown address --- src/analyses/memOutOfBounds.ml | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/analyses/memOutOfBounds.ml b/src/analyses/memOutOfBounds.ml index de18021278..9f9708335f 100644 --- a/src/analyses/memOutOfBounds.ml +++ b/src/analyses/memOutOfBounds.ml @@ -162,6 +162,22 @@ struct let remaining_offset = offs_to_idx typ o in IntDomain.IntDomTuple.add bytes_offset remaining_offset + let check_unknown_addr_deref ctx ptr = + let may_contain_unknown_addr = + match ctx.ask (Queries.EvalValue ptr) with + | a when not (Queries.VD.is_top a) -> + begin match a with + | Address a -> ValueDomain.AD.may_be_unknown a + | _ -> false + end + (* Intuition: if ptr evaluates to top, it could potentially evaluate to the unknown address *) + | _ -> true + in + if may_contain_unknown_addr then begin + set_mem_safety_flag InvalidDeref; + M.warn ~category:(Behavior (Undefined Other)) "Pointer %a contains an unknown address. Invalid dereference may occur" d_exp ptr + end + let ptr_only_has_str_addr ctx ptr = match ctx.ask (Queries.EvalValue ptr) with | a when not (Queries.VD.is_top a) -> @@ -230,6 +246,7 @@ struct end and check_no_binop_deref ctx lval_exp = + check_unknown_addr_deref ctx lval_exp; let behavior = Undefined MemoryOutOfBoundsAccess in let cwe_number = 823 in let ptr_size = get_size_of_ptr_target ctx lval_exp in @@ -276,6 +293,7 @@ struct | AddrOf lval -> check_lval_for_oob_access ctx ~is_implicitly_derefed lval and check_binop_exp ctx binop e1 e2 t = + check_unknown_addr_deref ctx e1; let binopexp = BinOp (binop, e1, e2, t) in let behavior = Undefined MemoryOutOfBoundsAccess in let cwe_number = 823 in From 3c014186d9f77bec2e734828aee0c1caf8a24b6b Mon Sep 17 00:00:00 2001 From: Stanimir Bozhilov Date: Wed, 13 Sep 2023 15:14:54 +0200 Subject: [PATCH 013/140] Remove unused function --- src/analyses/memOutOfBounds.ml | 27 --------------------------- 1 file changed, 27 deletions(-) diff --git a/src/analyses/memOutOfBounds.ml b/src/analyses/memOutOfBounds.ml index 9f9708335f..01bc12d7cb 100644 --- a/src/analyses/memOutOfBounds.ml +++ b/src/analyses/memOutOfBounds.ml @@ -23,33 +23,6 @@ struct let intdom_of_int x = IntDomain.IntDomTuple.of_int (Cilfacade.ptrdiff_ikind ()) (Z.of_int x) - let to_index ?typ offs = - let idx_of_int x = - IntDomain.IntDomTuple.of_int (Cilfacade.ptrdiff_ikind ()) (Z.of_int (x / 8)) - in - let rec offset_to_index_offset ?typ offs = match offs with - | `NoOffset -> idx_of_int 0 - | `Field (field, o) -> - let field_as_offset = Field (field, NoOffset) in - let bits_offset, _size = GoblintCil.bitsOffset (TComp (field.fcomp, [])) field_as_offset in - let bits_offset = idx_of_int bits_offset in - let remaining_offset = offset_to_index_offset ~typ:field.ftype o in - IntDomain.IntDomTuple.add bits_offset remaining_offset - | `Index (x, o) -> - let (item_typ, item_size_in_bits) = - match Option.map unrollType typ with - | Some TArray(item_typ, _, _) -> - let item_size_in_bits = bitsSizeOf item_typ in - (Some item_typ, idx_of_int item_size_in_bits) - | _ -> - (None, IntDomain.IntDomTuple.top_of @@ Cilfacade.ptrdiff_ikind ()) - in - let bits_offset = IntDomain.IntDomTuple.mul item_size_in_bits x in - let remaining_offset = offset_to_index_offset ?typ:item_typ o in - IntDomain.IntDomTuple.add bits_offset remaining_offset - in - offset_to_index_offset ?typ offs - let rec exp_contains_a_ptr (exp:exp) = match exp with | Const _ From 15f782b9efd276da84cbbf8121f04eb2e47101b8 Mon Sep 17 00:00:00 2001 From: Stanimir Bozhilov Date: Wed, 13 Sep 2023 15:25:44 +0200 Subject: [PATCH 014/140] Add exception handling for intdom arithmetic in memOutOfBounds --- src/analyses/memOutOfBounds.ml | 33 +++++++++++++++++++++++++-------- 1 file changed, 25 insertions(+), 8 deletions(-) diff --git a/src/analyses/memOutOfBounds.ml b/src/analyses/memOutOfBounds.ml index 01bc12d7cb..61e1b1a808 100644 --- a/src/analyses/memOutOfBounds.ml +++ b/src/analyses/memOutOfBounds.ml @@ -77,7 +77,11 @@ struct let item_typ_size_in_bytes = (bitsSizeOf item_typ) / 8 in let item_typ_size_in_bytes = intdom_of_int item_typ_size_in_bytes in begin match ctx.ask (Queries.EvalLength ptr) with - | `Lifted arr_len -> `Lifted (IntDomain.IntDomTuple.mul item_typ_size_in_bytes arr_len) + | `Lifted arr_len -> + begin + try `Lifted (IntDomain.IntDomTuple.mul item_typ_size_in_bytes arr_len) + with IntDomain.ArithmeticOnIntegerBot _ -> VDQ.ID.bot () + end | `Bot -> VDQ.ID.bot () | `Top -> VDQ.ID.top () end @@ -116,7 +120,10 @@ struct | `Lifted i -> (* The offset must be casted to ptrdiff_ikind in order to have matching ikinds for the multiplication below *) let casted_offset = IntDomain.IntDomTuple.cast_to (Cilfacade.ptrdiff_ikind ()) i in - `Lifted (IntDomain.IntDomTuple.mul casted_offset ptr_contents_typ_size_in_bytes) + begin + try `Lifted (IntDomain.IntDomTuple.mul casted_offset ptr_contents_typ_size_in_bytes) + with IntDomain.ArithmeticOnIntegerBot _ -> `Bot + end | `Top -> `Top | `Bot -> `Bot @@ -128,12 +135,18 @@ struct let bits_offset, _size = GoblintCil.bitsOffset (TComp (field.fcomp, [])) field_as_offset in let bytes_offset = intdom_of_int (bits_offset / 8) in let remaining_offset = offs_to_idx field.ftype o in - IntDomain.IntDomTuple.add bytes_offset remaining_offset + begin + try IntDomain.IntDomTuple.add bytes_offset remaining_offset + with IntDomain.ArithmeticOnIntegerBot _ -> IntDomain.IntDomTuple.bot_of @@ Cilfacade.ptrdiff_ikind () + end | `Index (x, o) -> - let typ_size_in_bytes = size_of_type_in_bytes typ in - let bytes_offset = IntDomain.IntDomTuple.mul typ_size_in_bytes x in - let remaining_offset = offs_to_idx typ o in - IntDomain.IntDomTuple.add bytes_offset remaining_offset + begin try + let typ_size_in_bytes = size_of_type_in_bytes typ in + let bytes_offset = IntDomain.IntDomTuple.mul typ_size_in_bytes x in + let remaining_offset = offs_to_idx typ o in + IntDomain.IntDomTuple.add bytes_offset remaining_offset + with IntDomain.ArithmeticOnIntegerBot _ -> IntDomain.IntDomTuple.bot_of @@ Cilfacade.ptrdiff_ikind () + end let check_unknown_addr_deref ctx ptr = let may_contain_unknown_addr = @@ -283,7 +296,11 @@ struct let offset_size = eval_ptr_offset_in_binop ctx e2 t in (* Make sure to add the address offset to the binop offset *) let offset_size_with_addr_size = match offset_size with - | `Lifted os -> `Lifted (IntDomain.IntDomTuple.add os addr_offs) + | `Lifted os -> + begin + try `Lifted (IntDomain.IntDomTuple.add os addr_offs) + with IntDomain.ArithmeticOnIntegerBot _ -> `Bot + end | `Top -> `Top | `Bot -> `Bot in From 20433e34c968f8c413bb1042f1165f547a70f203 Mon Sep 17 00:00:00 2001 From: Stanimir Bozhilov Date: Wed, 13 Sep 2023 17:15:58 +0200 Subject: [PATCH 015/140] Ignore info messages for test case 77/05 due to MacOS CI --- tests/regression/77-mem-oob/05-oob-implicit-deref.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tests/regression/77-mem-oob/05-oob-implicit-deref.c b/tests/regression/77-mem-oob/05-oob-implicit-deref.c index 088493d3b9..8bec6a72e0 100644 --- a/tests/regression/77-mem-oob/05-oob-implicit-deref.c +++ b/tests/regression/77-mem-oob/05-oob-implicit-deref.c @@ -1,4 +1,8 @@ -// PARAM: --set ana.activated[+] memOutOfBounds --enable ana.int.interval +// PARAM: --set ana.activated[+] memOutOfBounds --enable ana.int.interval --disable warn.info +/* + Note: the "--disable warn.info" above is a temporary workaround, + since the GitHub CI seems to be considering Info messages as violations of NOWARN (cf. https://github.com/goblint/analyzer/issues/1151) +*/ #include #include #include From 1116ef622f21fb53e82780317c19088c9bad25de Mon Sep 17 00:00:00 2001 From: Michael Schwarz Date: Sun, 24 Sep 2023 14:22:35 +0200 Subject: [PATCH 016/140] No shortcut `meet` and `narrow` w/ int refinement --- src/domains/lattice.ml | 9 +++++++-- .../regression/38-int-refinements/06-narrow.c | 18 ++++++++++++++++++ 2 files changed, 25 insertions(+), 2 deletions(-) create mode 100644 tests/regression/38-int-refinements/06-narrow.c diff --git a/src/domains/lattice.ml b/src/domains/lattice.ml index 4cdaa8fb9f..841d1d61b7 100644 --- a/src/domains/lattice.ml +++ b/src/domains/lattice.ml @@ -151,10 +151,15 @@ end module HConsed (Base:S) = struct include Printable.HConsed (Base) + + (* We do refine int values on narrow and meet {!IntDomain.IntDomTupleImpl}, which can lead to fixpoint issues *) + (* see https://github.com/goblint/analyzer/issues/1005 *) + let int_refine_active = GobConfig.get_string "ana.int.refinement" <> "never" + let lift_f2 f x y = f (unlift x) (unlift y) - let narrow x y = if x.BatHashcons.tag == y.BatHashcons.tag then x else lift (lift_f2 Base.narrow x y) + let narrow x y = if (not int_refine_active) && x.BatHashcons.tag == y.BatHashcons.tag then x else lift (lift_f2 Base.narrow x y) let widen x y = if x.BatHashcons.tag == y.BatHashcons.tag then x else lift (lift_f2 Base.widen x y) - let meet x y = if x.BatHashcons.tag == y.BatHashcons.tag then x else lift (lift_f2 Base.meet x y) + let meet x y = if (not int_refine_active) && x.BatHashcons.tag == y.BatHashcons.tag then x else lift (lift_f2 Base.meet x y) let join x y = if x.BatHashcons.tag == y.BatHashcons.tag then x else lift (lift_f2 Base.join x y) let leq x y = (x.BatHashcons.tag == y.BatHashcons.tag) || lift_f2 Base.leq x y let is_top = lift_f Base.is_top diff --git a/tests/regression/38-int-refinements/06-narrow.c b/tests/regression/38-int-refinements/06-narrow.c new file mode 100644 index 0000000000..513e9dde60 --- /dev/null +++ b/tests/regression/38-int-refinements/06-narrow.c @@ -0,0 +1,18 @@ +// PARAM: --set ana.int.refinement fixpoint --enable ana.int.interval +// FIXPOINT +#include + +int g = 0; + +void main() +{ + int i = 0; + while (1) { + i++; + for (int j=0; j < 10; j++) { + if (i > 100) g = 1; + } + if (i>9) i=0; + } + return; +} From 2f691be58f2367cdf2f8fb51e7fcf947b0571df3 Mon Sep 17 00:00:00 2001 From: Michael Schwarz Date: Sun, 24 Sep 2023 14:23:42 +0200 Subject: [PATCH 017/140] Make comment a bit longer --- src/domains/lattice.ml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/domains/lattice.ml b/src/domains/lattice.ml index 841d1d61b7..3e1207b8b1 100644 --- a/src/domains/lattice.ml +++ b/src/domains/lattice.ml @@ -152,7 +152,7 @@ module HConsed (Base:S) = struct include Printable.HConsed (Base) - (* We do refine int values on narrow and meet {!IntDomain.IntDomTupleImpl}, which can lead to fixpoint issues *) + (* We do refine int values on narrow and meet {!IntDomain.IntDomTupleImpl}, which can lead to fixpoint issues if we assume x op x = x *) (* see https://github.com/goblint/analyzer/issues/1005 *) let int_refine_active = GobConfig.get_string "ana.int.refinement" <> "never" From 08d56aa0d8e6e13b1ff87fd11d3bdffc8218611a Mon Sep 17 00:00:00 2001 From: Michael Schwarz Date: Sun, 24 Sep 2023 16:51:17 +0200 Subject: [PATCH 018/140] Add argument to `threadenter` --- src/analyses/abortUnless.ml | 2 +- src/analyses/accessAnalysis.ml | 2 +- src/analyses/activeLongjmp.ml | 2 +- src/analyses/activeSetjmp.ml | 2 +- src/analyses/apron/relationAnalysis.apron.ml | 2 +- src/analyses/base.ml | 2 +- src/analyses/condVars.ml | 2 +- src/analyses/expsplit.ml | 2 +- src/analyses/extractPthread.ml | 2 +- src/analyses/fileUse.ml | 2 +- src/analyses/locksetAnalysis.ml | 2 +- src/analyses/mCP.ml | 12 ++++----- src/analyses/mallocFresh.ml | 2 +- src/analyses/malloc_null.ml | 2 +- src/analyses/modifiedSinceLongjmp.ml | 2 +- src/analyses/mutexTypeAnalysis.ml | 2 +- src/analyses/poisonVariables.ml | 2 +- src/analyses/pthreadSignals.ml | 2 +- src/analyses/region.ml | 2 +- src/analyses/spec.ml | 2 +- src/analyses/stackTrace.ml | 4 +-- src/analyses/symbLocks.ml | 2 +- src/analyses/taintPartialContexts.ml | 2 +- src/analyses/termination.ml | 2 +- src/analyses/threadAnalysis.ml | 2 +- src/analyses/threadEscape.ml | 2 +- src/analyses/threadFlag.ml | 2 +- src/analyses/threadId.ml | 8 +++--- src/analyses/threadReturn.ml | 2 +- src/analyses/tmpSpecial.ml | 2 +- src/analyses/tutorials/taint.ml | 2 +- src/analyses/tutorials/unitAnalysis.ml | 2 +- src/analyses/uninit.ml | 2 +- src/analyses/useAfterFree.ml | 4 +-- src/analyses/varEq.ml | 2 +- src/analyses/vla.ml | 2 +- src/analyses/wrapperFunctionAnalysis.ml | 2 +- src/framework/analyses.ml | 6 ++--- src/framework/constraints.ml | 27 ++++++++++---------- src/framework/control.ml | 6 ++--- src/framework/resultQuery.ml | 6 ++--- src/util/wideningTokens.ml | 2 +- src/witness/observerAnalysis.ml | 2 +- src/witness/witnessConstraints.ml | 4 +-- 44 files changed, 74 insertions(+), 73 deletions(-) diff --git a/src/analyses/abortUnless.ml b/src/analyses/abortUnless.ml index 813d999ac3..1c77803c7e 100644 --- a/src/analyses/abortUnless.ml +++ b/src/analyses/abortUnless.ml @@ -65,7 +65,7 @@ struct false let startstate v = false - let threadenter ctx lval f args = [false] + let threadenter ?(multiple=false) ctx lval f args = [false] let threadspawn ctx lval f args fctx = false let exitstate v = false end diff --git a/src/analyses/accessAnalysis.ml b/src/analyses/accessAnalysis.ml index e99aefa0e5..bd1ca528a7 100644 --- a/src/analyses/accessAnalysis.ml +++ b/src/analyses/accessAnalysis.ml @@ -54,7 +54,7 @@ struct (** We just lift start state, global and dependency functions: *) let startstate v = () - let threadenter ctx lval f args = [()] + let threadenter ?(multiple=false) ctx lval f args = [()] let exitstate v = () let context fd d = () diff --git a/src/analyses/activeLongjmp.ml b/src/analyses/activeLongjmp.ml index 9c9868e32f..43da8c6512 100644 --- a/src/analyses/activeLongjmp.ml +++ b/src/analyses/activeLongjmp.ml @@ -26,7 +26,7 @@ struct (* Initial values don't really matter: overwritten at longjmp call. *) let startstate v = D.bot () - let threadenter ctx lval f args = [D.bot ()] + let threadenter ?(multiple=false) ctx lval f args = [D.bot ()] let exitstate v = D.top () let query ctx (type a) (q: a Queries.t): a Queries.result = diff --git a/src/analyses/activeSetjmp.ml b/src/analyses/activeSetjmp.ml index 069111d3ba..a69bf4db95 100644 --- a/src/analyses/activeSetjmp.ml +++ b/src/analyses/activeSetjmp.ml @@ -25,7 +25,7 @@ struct | _ -> ctx.local let startstate v = D.bot () - let threadenter ctx lval f args = [D.bot ()] + let threadenter ?(multiple=false) ctx lval f args = [D.bot ()] let exitstate v = D.top () let query ctx (type a) (q: a Queries.t): a Queries.result = diff --git a/src/analyses/apron/relationAnalysis.apron.ml b/src/analyses/apron/relationAnalysis.apron.ml index 46c620f390..d56064a42f 100644 --- a/src/analyses/apron/relationAnalysis.apron.ml +++ b/src/analyses/apron/relationAnalysis.apron.ml @@ -647,7 +647,7 @@ struct (* Thread transfer functions. *) - let threadenter ctx lval f args = + let threadenter ?(multiple=false) ctx lval f args = let st = ctx.local in match Cilfacade.find_varinfo_fundec f with | fd -> diff --git a/src/analyses/base.ml b/src/analyses/base.ml index 71e2661997..cb29cbc0ab 100644 --- a/src/analyses/base.ml +++ b/src/analyses/base.ml @@ -2503,7 +2503,7 @@ struct in combine_one ctx.local after - let threadenter ctx (lval: lval option) (f: varinfo) (args: exp list): D.t list = + let threadenter ?(multiple=false) ctx (lval: lval option) (f: varinfo) (args: exp list): D.t list = match Cilfacade.find_varinfo_fundec f with | fd -> [make_entry ~thread:true ctx fd args] diff --git a/src/analyses/condVars.ml b/src/analyses/condVars.ml index 04b148dd02..3a2cc5798d 100644 --- a/src/analyses/condVars.ml +++ b/src/analyses/condVars.ml @@ -155,7 +155,7 @@ struct ctx.local let startstate v = D.bot () - let threadenter ctx lval f args = [D.bot ()] + let threadenter ?(multiple=false) ctx lval f args = [D.bot ()] let threadspawn ctx lval f args fctx = ctx.local let exitstate v = D.bot () end diff --git a/src/analyses/expsplit.ml b/src/analyses/expsplit.ml index f121d0380e..9c610a96bf 100644 --- a/src/analyses/expsplit.ml +++ b/src/analyses/expsplit.ml @@ -84,7 +84,7 @@ struct in emit_splits ctx d - let threadenter ctx lval f args = [ctx.local] + let threadenter ?(multiple=false) ctx lval f args = [ctx.local] let threadspawn ctx lval f args fctx = emit_splits_ctx ctx diff --git a/src/analyses/extractPthread.ml b/src/analyses/extractPthread.ml index 60e389fedf..591704cc70 100644 --- a/src/analyses/extractPthread.ml +++ b/src/analyses/extractPthread.ml @@ -1238,7 +1238,7 @@ module Spec : Analyses.MCPSpec = struct (Ctx.top ()) - let threadenter ctx lval f args = + let threadenter ?(multiple=false) ctx lval f args = let d : D.t = ctx.local in let tasks = ctx.global tasks_var in (* TODO: optimize finding *) diff --git a/src/analyses/fileUse.ml b/src/analyses/fileUse.ml index a9088a4bb2..b12953c71c 100644 --- a/src/analyses/fileUse.ml +++ b/src/analyses/fileUse.ml @@ -287,7 +287,7 @@ struct | _ -> m let startstate v = D.bot () - let threadenter ctx lval f args = [D.bot ()] + let threadenter ?(multiple=false) ctx lval f args = [D.bot ()] let threadspawn ctx lval f args fctx = ctx.local let exitstate v = D.bot () end diff --git a/src/analyses/locksetAnalysis.ml b/src/analyses/locksetAnalysis.ml index 2e9e08f03d..56fe960a47 100644 --- a/src/analyses/locksetAnalysis.ml +++ b/src/analyses/locksetAnalysis.ml @@ -18,7 +18,7 @@ struct module C = D let startstate v = D.empty () - let threadenter ctx lval f args = [D.empty ()] + let threadenter ?(multiple=false) ctx lval f args = [D.empty ()] let exitstate v = D.empty () end diff --git a/src/analyses/mCP.ml b/src/analyses/mCP.ml index 1b6a7e5a1d..e305e9c7f6 100644 --- a/src/analyses/mCP.ml +++ b/src/analyses/mCP.ml @@ -140,9 +140,9 @@ struct f ((k,v::a')::a) b in f [] xs - let do_spawns ctx (xs:(varinfo * (lval option * exp list)) list) = + let do_spawns ctx (xs:(varinfo * (lval option * exp list * bool)) list) = let spawn_one v d = - List.iter (fun (lval, args) -> ctx.spawn lval v args) d + List.iter (fun (lval, args, multiple) -> ctx.spawn ~multiple lval v args) d in if not (get_bool "exp.single-threaded") then iter (uncurry spawn_one) @@ group_assoc_eq Basetype.Variables.equal xs @@ -322,8 +322,8 @@ struct and outer_ctx tfname ?spawns ?sides ?emits ctx = let spawn = match spawns with - | Some spawns -> (fun l v a -> spawns := (v,(l,a)) :: !spawns) - | None -> (fun v d -> failwith ("Cannot \"spawn\" in " ^ tfname ^ " context.")) + | Some spawns -> (fun ?(multiple=false) l v a -> spawns := (v,(l,a,multiple)) :: !spawns) + | None -> (fun ?(multiple=false) v d -> failwith ("Cannot \"spawn\" in " ^ tfname ^ " context.")) in let sideg = match sides with | Some sides -> (fun v g -> sides := (v, (!WideningTokens.side_tokens, g)) :: !sides) @@ -565,13 +565,13 @@ struct let d = do_emits ctx !emits d q in if q then raise Deadcode else d - let threadenter (ctx:(D.t, G.t, C.t, V.t) ctx) lval f a = + let threadenter ?(multiple=false) (ctx:(D.t, G.t, C.t, V.t) ctx) lval f a = let sides = ref [] in let emits = ref [] in let ctx'' = outer_ctx "threadenter" ~sides ~emits ctx in let f (n,(module S:MCPSpec),d) = let ctx' : (S.D.t, S.G.t, S.C.t, S.V.t) ctx = inner_ctx "threadenter" ctx'' n d in - map (fun d -> (n, repr d)) @@ S.threadenter ctx' lval f a + map (fun d -> (n, repr d)) @@ (S.threadenter ~multiple) ctx' lval f a in let css = map f @@ spec_list ctx.local in do_sideg ctx !sides; diff --git a/src/analyses/mallocFresh.ml b/src/analyses/mallocFresh.ml index 2c2b99a075..861e4958bd 100644 --- a/src/analyses/mallocFresh.ml +++ b/src/analyses/mallocFresh.ml @@ -52,7 +52,7 @@ struct | None -> ctx.local | Some lval -> assign_lval (Analyses.ask_of_ctx ctx) lval ctx.local - let threadenter ctx lval f args = + let threadenter ?(multiple=false) ctx lval f args = [D.empty ()] let threadspawn ctx lval f args fctx = diff --git a/src/analyses/malloc_null.ml b/src/analyses/malloc_null.ml index 4d5871cb80..2d90112636 100644 --- a/src/analyses/malloc_null.ml +++ b/src/analyses/malloc_null.ml @@ -215,7 +215,7 @@ struct let name () = "malloc_null" let startstate v = D.empty () - let threadenter ctx lval f args = [D.empty ()] + let threadenter ?(multiple=false) ctx lval f args = [D.empty ()] let threadspawn ctx lval f args fctx = ctx.local let exitstate v = D.empty () diff --git a/src/analyses/modifiedSinceLongjmp.ml b/src/analyses/modifiedSinceLongjmp.ml index 0375bd3f74..d9c8f5102c 100644 --- a/src/analyses/modifiedSinceLongjmp.ml +++ b/src/analyses/modifiedSinceLongjmp.ml @@ -63,7 +63,7 @@ struct ctx.local let startstate v = D.bot () - let threadenter ctx lval f args = [D.bot ()] + let threadenter ?(multiple=false) ctx lval f args = [D.bot ()] let exitstate v = D.top () let query ctx (type a) (q: a Queries.t): a Queries.result = diff --git a/src/analyses/mutexTypeAnalysis.ml b/src/analyses/mutexTypeAnalysis.ml index 806c35f464..7051173bd0 100644 --- a/src/analyses/mutexTypeAnalysis.ml +++ b/src/analyses/mutexTypeAnalysis.ml @@ -65,7 +65,7 @@ struct | _ -> ctx.local let startstate v = D.bot () - let threadenter ctx lval f args = [D.top ()] + let threadenter ?(multiple=false) ctx lval f args = [D.top ()] let threadspawn ctx lval f args fctx = ctx.local let exitstate v = D.top () diff --git a/src/analyses/poisonVariables.ml b/src/analyses/poisonVariables.ml index 1bd4b6d544..8c79626cc9 100644 --- a/src/analyses/poisonVariables.ml +++ b/src/analyses/poisonVariables.ml @@ -61,7 +61,7 @@ struct VS.join au ctx.local let startstate v = D.bot () - let threadenter ctx lval f args = [D.bot ()] + let threadenter ?(multiple=false) ctx lval f args = [D.bot ()] let exitstate v = D.top () let event ctx e octx = diff --git a/src/analyses/pthreadSignals.ml b/src/analyses/pthreadSignals.ml index 0b776282e8..83455965ec 100644 --- a/src/analyses/pthreadSignals.ml +++ b/src/analyses/pthreadSignals.ml @@ -73,7 +73,7 @@ struct | _ -> ctx.local let startstate v = Signals.empty () - let threadenter ctx lval f args = [ctx.local] + let threadenter ?(multiple=false) ctx lval f args = [ctx.local] let exitstate v = Signals.empty () end diff --git a/src/analyses/region.ml b/src/analyses/region.ml index 6d2ae246c3..9d68221fcd 100644 --- a/src/analyses/region.ml +++ b/src/analyses/region.ml @@ -175,7 +175,7 @@ struct let startstate v = `Lifted (RegMap.bot ()) - let threadenter ctx lval f args = + let threadenter ?(multiple=false) ctx lval f args = [`Lifted (RegMap.bot ())] let threadspawn ctx lval f args fctx = ctx.local diff --git a/src/analyses/spec.ml b/src/analyses/spec.ml index 54ffcd2697..e5434eb264 100644 --- a/src/analyses/spec.ml +++ b/src/analyses/spec.ml @@ -487,7 +487,7 @@ struct let startstate v = D.bot () - let threadenter ctx lval f args = [D.bot ()] + let threadenter ?(multiple=false) ctx lval f args = [D.bot ()] let threadspawn ctx lval f args fctx = ctx.local let exitstate v = D.bot () end diff --git a/src/analyses/stackTrace.ml b/src/analyses/stackTrace.ml index 4dc62f1873..3d70c50856 100644 --- a/src/analyses/stackTrace.ml +++ b/src/analyses/stackTrace.ml @@ -21,7 +21,7 @@ struct ctx.local (* keep local as opposed to IdentitySpec *) let startstate v = D.bot () - let threadenter ctx lval f args = [D.bot ()] + let threadenter ?(multiple=false) ctx lval f args = [D.bot ()] let exitstate v = D.top () end @@ -45,7 +45,7 @@ struct let startstate v = D.bot () let exitstate v = D.top () - let threadenter ctx lval f args = + let threadenter ?(multiple=false) ctx lval f args = [D.push !Tracing.current_loc ctx.local] end diff --git a/src/analyses/symbLocks.ml b/src/analyses/symbLocks.ml index d8cebf51d2..b99ef93039 100644 --- a/src/analyses/symbLocks.ml +++ b/src/analyses/symbLocks.ml @@ -29,7 +29,7 @@ struct let name () = "symb_locks" let startstate v = D.top () - let threadenter ctx lval f args = [D.top ()] + let threadenter ?(multiple=false) ctx lval f args = [D.top ()] let threadspawn ctx lval f args fctx = ctx.local let exitstate v = D.top () diff --git a/src/analyses/taintPartialContexts.ml b/src/analyses/taintPartialContexts.ml index d053cd103b..25e981dcbf 100644 --- a/src/analyses/taintPartialContexts.ml +++ b/src/analyses/taintPartialContexts.ml @@ -101,7 +101,7 @@ struct d let startstate v = D.bot () - let threadenter ctx lval f args = + let threadenter ?(multiple=false) ctx lval f args = [D.bot ()] let threadspawn ctx lval f args fctx = match lval with diff --git a/src/analyses/termination.ml b/src/analyses/termination.ml index 6da9225d3f..5e5e0d36f1 100644 --- a/src/analyses/termination.ml +++ b/src/analyses/termination.ml @@ -217,7 +217,7 @@ struct (* | _ -> ctx.local *) let startstate v = D.bot () - let threadenter ctx lval f args = [D.bot ()] + let threadenter ?(multiple=false) ctx lval f args = [D.bot ()] let exitstate v = D.bot () end diff --git a/src/analyses/threadAnalysis.ml b/src/analyses/threadAnalysis.ml index 1e679a4707..26e6702c25 100644 --- a/src/analyses/threadAnalysis.ml +++ b/src/analyses/threadAnalysis.ml @@ -84,7 +84,7 @@ struct | _ -> Queries.Result.top q let startstate v = D.bot () - let threadenter ctx lval f args = [D.bot ()] + let threadenter ?(multiple=false) ctx lval f args = [D.bot ()] let threadspawn ctx lval f args fctx = let creator = ThreadId.get_current (Analyses.ask_of_ctx ctx) in let tid = ThreadId.get_current_unlift (Analyses.ask_of_ctx fctx) in diff --git a/src/analyses/threadEscape.ml b/src/analyses/threadEscape.ml index 9ed62e7422..0674ebf3d1 100644 --- a/src/analyses/threadEscape.ml +++ b/src/analyses/threadEscape.ml @@ -150,7 +150,7 @@ struct let startstate v = D.bot () let exitstate v = D.bot () - let threadenter ctx lval f args = + let threadenter ?(multiple=false) ctx lval f args = [D.bot ()] let threadspawn ctx lval f args fctx = diff --git a/src/analyses/threadFlag.ml b/src/analyses/threadFlag.ml index f2ebf82be1..f3b132918a 100644 --- a/src/analyses/threadFlag.ml +++ b/src/analyses/threadFlag.ml @@ -58,7 +58,7 @@ struct let access ctx _ = is_currently_multi (Analyses.ask_of_ctx ctx) - let threadenter ctx lval f args = + let threadenter ?(multiple=false) ctx lval f args = if not (has_ever_been_multi (Analyses.ask_of_ctx ctx)) then ctx.emit Events.EnterMultiThreaded; [create_tid f] diff --git a/src/analyses/threadId.ml b/src/analyses/threadId.ml index 4acf88a7ef..f1de1dfdcb 100644 --- a/src/analyses/threadId.ml +++ b/src/analyses/threadId.ml @@ -56,9 +56,9 @@ struct Hashtbl.replace !tids tid (); (N.bot (), `Lifted (tid), (TD.bot (), TD.bot ())) - let create_tid (_, current, (td, _)) ((node, index): Node.t * int option) v = + let create_tid ?(multiple=false) (_, current, (td, _)) ((node, index): Node.t * int option) v = match current with - | `Lifted current -> + | `Lifted current when not multiple -> let+ tid = Thread.threadenter (current, td) node index v in if GobConfig.get_bool "dbg.print_tids" then Hashtbl.replace !tids tid (); @@ -133,9 +133,9 @@ struct | `Lifted node, count -> node, Some count | (`Bot | `Top), _ -> ctx.prev_node, None - let threadenter ctx lval f args:D.t list = + let threadenter ?(multiple=false) ctx lval f args:D.t list = let n, i = indexed_node_for_ctx ctx in - let+ tid = create_tid ctx.local (n, i) f in + let+ tid = create_tid ~multiple ctx.local (n, i) f in (`Lifted (f, n, i), tid, (TD.bot (), TD.bot ())) let threadspawn ctx lval f args fctx = diff --git a/src/analyses/threadReturn.ml b/src/analyses/threadReturn.ml index 470c4ceaa8..176a4d3465 100644 --- a/src/analyses/threadReturn.ml +++ b/src/analyses/threadReturn.ml @@ -28,7 +28,7 @@ struct ctx.local (* keep local as opposed to IdentitySpec *) let startstate v = true - let threadenter ctx lval f args = [true] + let threadenter ?(multiple=false) ctx lval f args = [true] let exitstate v = D.top () let query (ctx: (D.t, _, _, _) ctx) (type a) (x: a Queries.t): a Queries.result = diff --git a/src/analyses/tmpSpecial.ml b/src/analyses/tmpSpecial.ml index 2d38972d7a..f3d092e59e 100644 --- a/src/analyses/tmpSpecial.ml +++ b/src/analyses/tmpSpecial.ml @@ -88,7 +88,7 @@ struct | _ -> Queries.Result.top q let startstate v = D.bot () - let threadenter ctx lval f args = [D.bot ()] + let threadenter ?(multiple=false) ctx lval f args = [D.bot ()] let threadspawn ctx lval f args fctx = ctx.local let exitstate v = D.bot () end diff --git a/src/analyses/tutorials/taint.ml b/src/analyses/tutorials/taint.ml index 3067449e31..166ce2c3f6 100644 --- a/src/analyses/tutorials/taint.ml +++ b/src/analyses/tutorials/taint.ml @@ -129,7 +129,7 @@ struct (* You may leave these alone *) let startstate v = D.bot () - let threadenter ctx lval f args = [D.top ()] + let threadenter ?(multiple=false) ctx lval f args = [D.top ()] let threadspawn ctx lval f args fctx = ctx.local let exitstate v = D.top () end diff --git a/src/analyses/tutorials/unitAnalysis.ml b/src/analyses/tutorials/unitAnalysis.ml index d3b8c69bfd..b5fb4d6367 100644 --- a/src/analyses/tutorials/unitAnalysis.ml +++ b/src/analyses/tutorials/unitAnalysis.ml @@ -39,7 +39,7 @@ struct ctx.local let startstate v = D.bot () - let threadenter ctx lval f args = [D.top ()] + let threadenter ?(multiple=false) ctx lval f args = [D.top ()] let threadspawn ctx lval f args fctx = ctx.local let exitstate v = D.top () end diff --git a/src/analyses/uninit.ml b/src/analyses/uninit.ml index f8759d9134..abdcd67aaa 100644 --- a/src/analyses/uninit.ml +++ b/src/analyses/uninit.ml @@ -25,7 +25,7 @@ struct let name () = "uninit" let startstate v : D.t = D.empty () - let threadenter ctx lval f args = [D.empty ()] + let threadenter ?(multiple=false) ctx lval f args = [D.empty ()] let threadspawn ctx lval f args fctx = ctx.local let exitstate v : D.t = D.empty () diff --git a/src/analyses/useAfterFree.ml b/src/analyses/useAfterFree.ml index 0aafbd1ad4..6033c689e1 100644 --- a/src/analyses/useAfterFree.ml +++ b/src/analyses/useAfterFree.ml @@ -196,7 +196,7 @@ struct end | _ -> state - let threadenter ctx lval f args = [ctx.local] + let threadenter ?(multiple=false) ctx lval f args = [ctx.local] let threadspawn ctx lval f args fctx = ctx.local let startstate v = D.bot () @@ -205,4 +205,4 @@ struct end let _ = - MCP.register_analysis (module Spec : MCPSpec) \ No newline at end of file + MCP.register_analysis (module Spec : MCPSpec) diff --git a/src/analyses/varEq.ml b/src/analyses/varEq.ml index 634a684c7c..7bd3453b8a 100644 --- a/src/analyses/varEq.ml +++ b/src/analyses/varEq.ml @@ -43,7 +43,7 @@ struct let name () = "var_eq" let startstate v = D.top () - let threadenter ctx lval f args = [D.top ()] + let threadenter ?(multiple=false) ctx lval f args = [D.top ()] let threadspawn ctx lval f args fctx = ctx.local let exitstate v = D.top () diff --git a/src/analyses/vla.ml b/src/analyses/vla.ml index 865f22b20a..8bd0168de0 100644 --- a/src/analyses/vla.ml +++ b/src/analyses/vla.ml @@ -33,7 +33,7 @@ struct ctx.local || Cilfacade.isVLAType v.vtype let startstate v = D.bot () - let threadenter ctx lval f args = [D.top ()] + let threadenter ?(multiple=false) ctx lval f args = [D.top ()] let exitstate v = D.top () end diff --git a/src/analyses/wrapperFunctionAnalysis.ml b/src/analyses/wrapperFunctionAnalysis.ml index d9bbdb6197..89242e044e 100644 --- a/src/analyses/wrapperFunctionAnalysis.ml +++ b/src/analyses/wrapperFunctionAnalysis.ml @@ -87,7 +87,7 @@ struct let startstate v = D.bot () - let threadenter ctx lval f args = + let threadenter ?(multiple=false) ctx lval f args = (* The new thread receives a fresh counter *) [D.bot ()] diff --git a/src/framework/analyses.ml b/src/framework/analyses.ml index df3346af93..54a3a18f1a 100644 --- a/src/framework/analyses.ml +++ b/src/framework/analyses.ml @@ -342,7 +342,7 @@ type ('d,'g,'c,'v) ctx = ; edge : MyCFG.edge ; local : 'd ; global : 'v -> 'g - ; spawn : lval option -> varinfo -> exp list -> unit + ; spawn : ?multiple:bool -> lval option -> varinfo -> exp list -> unit ; split : 'd -> Events.t list -> unit ; sideg : 'v -> 'g -> unit } @@ -444,7 +444,7 @@ sig val paths_as_set : (D.t, G.t, C.t, V.t) ctx -> D.t list (** Returns initial state for created thread. *) - val threadenter : (D.t, G.t, C.t, V.t) ctx -> lval option -> varinfo -> exp list -> D.t list + val threadenter : ?multiple:bool -> (D.t, G.t, C.t, V.t) ctx -> lval option -> varinfo -> exp list -> D.t list (** Updates the local state of the creator thread using initial state of created thread. *) val threadspawn : (D.t, G.t, C.t, V.t) ctx -> lval option -> varinfo -> exp list -> (D.t, G.t, C.t, V.t) ctx -> D.t @@ -696,7 +696,7 @@ struct let special ctx (lval: lval option) (f:varinfo) (arglist:exp list) = ctx.local - let threadenter ctx lval f args = [ctx.local] + let threadenter ?(multiple=false) ctx lval f args = [ctx.local] let threadspawn ctx lval f args fctx = ctx.local end diff --git a/src/framework/constraints.ml b/src/framework/constraints.ml index 740d1f85a9..a7683fb6b3 100644 --- a/src/framework/constraints.ml +++ b/src/framework/constraints.ml @@ -83,8 +83,8 @@ struct let combine_assign ctx r fe f args fc es f_ask = D.lift @@ S.combine_assign (conv ctx) r fe f args fc (D.unlift es) f_ask - let threadenter ctx lval f args = - List.map D.lift @@ S.threadenter (conv ctx) lval f args + let threadenter ?(multiple=false) ctx lval f args = + List.map D.lift @@ (S.threadenter ~multiple) (conv ctx) lval f args let threadspawn ctx lval f args fctx = D.lift @@ S.threadspawn (conv ctx) lval f args (conv fctx) @@ -167,8 +167,8 @@ struct let combine_assign ctx r fe f args fc es f_ask = S.combine_assign (conv ctx) r fe f args (Option.map C.unlift fc) es f_ask - let threadenter ctx lval f args = - S.threadenter (conv ctx) lval f args + let threadenter ?(multiple=false) ctx lval f args = + S.threadenter ~multiple (conv ctx) lval f args let threadspawn ctx lval f args fctx = S.threadspawn (conv ctx) lval f args (conv fctx) @@ -249,7 +249,7 @@ struct let combine_env' ctx r fe f args fc es f_ask = lift_fun ctx (lift ctx) S.combine_env (fun p -> p r fe f args fc (fst es) f_ask) let combine_assign' ctx r fe f args fc es f_ask = lift_fun ctx (lift ctx) S.combine_assign (fun p -> p r fe f args fc (fst es) f_ask) - let threadenter ctx lval f args = lift_fun ctx (List.map lift_start_level) S.threadenter ((|>) args % (|>) f % (|>) lval) + let threadenter ?(multiple=false) ctx lval f args = lift_fun ctx (List.map lift_start_level) (S.threadenter ~multiple) ((|>) args % (|>) f % (|>) lval) let threadspawn ctx lval f args fctx = lift_fun ctx (lift ctx) S.threadspawn ((|>) (conv fctx) % (|>) args % (|>) f % (|>) lval) let leq0 = function @@ -394,7 +394,7 @@ struct let event ctx e octx = lift_fun ctx S.event ((|>) (conv octx) % (|>) e) - let threadenter ctx lval f args = S.threadenter (conv ctx) lval f args |> List.map (fun d -> (d, snd ctx.local)) + let threadenter ?(multiple=false) ctx lval f args = S.threadenter ~multiple (conv ctx) lval f args |> List.map (fun d -> (d, snd ctx.local)) let threadspawn ctx lval f args fctx = lift_fun ctx S.threadspawn ((|>) (conv fctx) % (|>) args % (|>) f % (|>) lval) let enter ctx r f args = @@ -485,7 +485,7 @@ struct let combine_env ctx r fe f args fc es f_ask = lift_fun ctx D.lift S.combine_env (fun p -> p r fe f args fc (D.unlift es) f_ask) `Bot let combine_assign ctx r fe f args fc es f_ask = lift_fun ctx D.lift S.combine_assign (fun p -> p r fe f args fc (D.unlift es) f_ask) `Bot - let threadenter ctx lval f args = lift_fun ctx (List.map D.lift) S.threadenter ((|>) args % (|>) f % (|>) lval) [] + let threadenter ?(multiple=false) ctx lval f args = lift_fun ctx (List.map D.lift) (S.threadenter ~multiple) ((|>) args % (|>) f % (|>) lval) [] let threadspawn ctx lval f args fctx = lift_fun ctx D.lift S.threadspawn ((|>) (conv fctx) % (|>) args % (|>) f % (|>) lval) `Bot let event (ctx:(D.t,G.t,C.t,V.t) ctx) (e:Events.t) (octx:(D.t,G.t,C.t,V.t) ctx):D.t = lift_fun ctx D.lift S.event ((|>) (conv octx) % (|>) e) `Bot @@ -581,7 +581,7 @@ struct ; split = (fun (d:D.t) es -> assert (List.is_empty es); r := d::!r) ; sideg = (fun g d -> sideg (GVar.spec g) (G.create_spec d)) } - and spawn lval f args = + and spawn ?(multiple=false) lval f args = (* TODO: adjust ctx node/edge? *) (* TODO: don't repeat for all paths that spawn same *) let ds = S.threadenter ctx lval f args in @@ -898,7 +898,7 @@ struct ; edge = MyCFG.Skip ; local = S.startstate Cil.dummyFunDec.svar (* bot and top both silently raise and catch Deadcode in DeadcodeLifter *) ; global = (fun g -> G.spec (getg (GVar.spec g))) - ; spawn = (fun v d -> failwith "Cannot \"spawn\" in query context.") + ; spawn = (fun ?(multiple=false) v d -> failwith "Cannot \"spawn\" in query context.") ; split = (fun d es -> failwith "Cannot \"split\" in query context.") ; sideg = (fun v g -> failwith "Cannot \"split\" in query context.") } @@ -1262,9 +1262,10 @@ struct let fd1 = D.choose octx.local in map ctx Spec.event (fun h -> h e (conv octx fd1)) - let threadenter ctx lval f args = + let threadenter ?(multiple=false) ctx lval f args = let g xs ys = (List.map (fun y -> D.singleton y) ys) @ xs in - fold' ctx Spec.threadenter (fun h -> h lval f args) g [] + fold' ctx (Spec.threadenter ~multiple) (fun h -> h lval f args) g [] + let threadspawn ctx lval f args fctx = let fd1 = D.choose fctx.local in map ctx Spec.threadspawn (fun h -> h lval f args (conv fctx fd1)) @@ -1448,7 +1449,7 @@ struct let combine_env ctx = S.combine_env (conv ctx) let combine_assign ctx = S.combine_assign (conv ctx) let special ctx = S.special (conv ctx) - let threadenter ctx = S.threadenter (conv ctx) + let threadenter ?(multiple=false) ctx = S.threadenter ~multiple (conv ctx) let threadspawn ctx lv f args fctx = S.threadspawn (conv ctx) lv f args (conv fctx) let sync ctx = S.sync (conv ctx) let skip ctx = S.skip (conv ctx) @@ -1684,7 +1685,7 @@ struct List.iter handle_path (S.paths_as_set conv_ctx); S.D.bot () | _ -> S.special conv_ctx lv f args - let threadenter ctx = S.threadenter (conv ctx) + let threadenter ?(multiple=false) ctx = S.threadenter ~multiple (conv ctx) let threadspawn ctx lv f args fctx = S.threadspawn (conv ctx) lv f args (conv fctx) let sync ctx = S.sync (conv ctx) let skip ctx = S.skip (conv ctx) diff --git a/src/framework/control.ml b/src/framework/control.ml index 5cefc1a7de..72890be4b4 100644 --- a/src/framework/control.ml +++ b/src/framework/control.ml @@ -280,7 +280,7 @@ struct ; edge = MyCFG.Skip ; local = Spec.D.top () ; global = (fun g -> EQSys.G.spec (getg (EQSys.GVar.spec g))) - ; spawn = (fun _ -> failwith "Global initializers should never spawn threads. What is going on?") + ; spawn = (fun ?(multiple=false) _ -> failwith "Global initializers should never spawn threads. What is going on?") ; split = (fun _ -> failwith "Global initializers trying to split paths.") ; sideg = (fun g d -> sideg (EQSys.GVar.spec g) (EQSys.G.create_spec d)) } @@ -385,7 +385,7 @@ struct ; edge = MyCFG.Skip ; local = st ; global = (fun g -> EQSys.G.spec (getg (EQSys.GVar.spec g))) - ; spawn = (fun _ -> failwith "Bug1: Using enter_func for toplevel functions with 'otherstate'.") + ; spawn = (fun ?(multiple=false) _ -> failwith "Bug1: Using enter_func for toplevel functions with 'otherstate'.") ; split = (fun _ -> failwith "Bug2: Using enter_func for toplevel functions with 'otherstate'.") ; sideg = (fun g d -> sideg (EQSys.GVar.spec g) (EQSys.G.create_spec d)) } @@ -417,7 +417,7 @@ struct ; edge = MyCFG.Skip ; local = st ; global = (fun g -> EQSys.G.spec (getg (EQSys.GVar.spec g))) - ; spawn = (fun _ -> failwith "Bug1: Using enter_func for toplevel functions with 'otherstate'.") + ; spawn = (fun ?(multiple=false) _ -> failwith "Bug1: Using enter_func for toplevel functions with 'otherstate'.") ; split = (fun _ -> failwith "Bug2: Using enter_func for toplevel functions with 'otherstate'.") ; sideg = (fun g d -> sideg (EQSys.GVar.spec g) (EQSys.G.create_spec d)) } diff --git a/src/framework/resultQuery.ml b/src/framework/resultQuery.ml index ce5839ef30..c676c41c14 100644 --- a/src/framework/resultQuery.ml +++ b/src/framework/resultQuery.ml @@ -18,7 +18,7 @@ struct ; edge = MyCFG.Skip ; local = local ; global = (fun g -> try EQSys.G.spec (GHT.find gh (EQSys.GVar.spec g)) with Not_found -> Spec.G.bot ()) (* see 29/29 on why fallback is needed *) - ; spawn = (fun v d -> failwith "Cannot \"spawn\" in witness context.") + ; spawn = (fun ?(multiple=false) v d -> failwith "Cannot \"spawn\" in witness context.") ; split = (fun d es -> failwith "Cannot \"split\" in witness context.") ; sideg = (fun v g -> failwith "Cannot \"sideg\" in witness context.") } @@ -37,7 +37,7 @@ struct ; edge = MyCFG.Skip ; local = local ; global = (fun g -> try EQSys.G.spec (GHT.find gh (EQSys.GVar.spec g)) with Not_found -> Spec.G.bot ()) (* TODO: how can be missing? *) - ; spawn = (fun v d -> failwith "Cannot \"spawn\" in witness context.") + ; spawn = (fun ?(multiple=false) v d -> failwith "Cannot \"spawn\" in witness context.") ; split = (fun d es -> failwith "Cannot \"split\" in witness context.") ; sideg = (fun v g -> failwith "Cannot \"sideg\" in witness context.") } @@ -57,7 +57,7 @@ struct ; edge = MyCFG.Skip ; local = Spec.startstate GoblintCil.dummyFunDec.svar (* bot and top both silently raise and catch Deadcode in DeadcodeLifter *) (* TODO: is this startstate bad? *) ; global = (fun v -> EQSys.G.spec (try GHT.find gh (EQSys.GVar.spec v) with Not_found -> EQSys.G.bot ())) (* TODO: how can be missing? *) - ; spawn = (fun v d -> failwith "Cannot \"spawn\" in query context.") + ; spawn = (fun ?(multiple=false) v d -> failwith "Cannot \"spawn\" in query context.") ; split = (fun d es -> failwith "Cannot \"split\" in query context.") ; sideg = (fun v g -> failwith "Cannot \"split\" in query context.") } diff --git a/src/util/wideningTokens.ml b/src/util/wideningTokens.ml index 75f0e4f81d..c88f3f00c1 100644 --- a/src/util/wideningTokens.ml +++ b/src/util/wideningTokens.ml @@ -179,7 +179,7 @@ struct let combine_env ctx r fe f args fc es f_ask = lift_fun ctx lift' S.combine_env (fun p -> p r fe f args fc (D.unlift es) f_ask) (* TODO: use tokens from es *) let combine_assign ctx r fe f args fc es f_ask = lift_fun ctx lift' S.combine_assign (fun p -> p r fe f args fc (D.unlift es) f_ask) (* TODO: use tokens from es *) - let threadenter ctx lval f args = lift_fun ctx (fun l ts -> List.map (Fun.flip lift' ts) l) S.threadenter ((|>) args % (|>) f % (|>) lval) + let threadenter ?(multiple=false) ctx lval f args = lift_fun ctx (fun l ts -> List.map (Fun.flip lift' ts) l) (S.threadenter ~multiple) ((|>) args % (|>) f % (|>) lval ) let threadspawn ctx lval f args fctx = lift_fun ctx lift' S.threadspawn ((|>) (conv fctx) % (|>) args % (|>) f % (|>) lval) let event ctx e octx = lift_fun ctx lift' S.event ((|>) (conv octx) % (|>) e) end diff --git a/src/witness/observerAnalysis.ml b/src/witness/observerAnalysis.ml index c8d8563909..3c702d199f 100644 --- a/src/witness/observerAnalysis.ml +++ b/src/witness/observerAnalysis.ml @@ -76,7 +76,7 @@ struct step_ctx ctx let startstate v = `Lifted Automaton.initial - let threadenter ctx lval f args = [D.top ()] + let threadenter ?(multiple=false) ctx lval f args = [D.top ()] let threadspawn ctx lval f args fctx = ctx.local let exitstate v = D.top () end diff --git a/src/witness/witnessConstraints.ml b/src/witness/witnessConstraints.ml index 2ce16a5997..ad32713fa8 100644 --- a/src/witness/witnessConstraints.ml +++ b/src/witness/witnessConstraints.ml @@ -199,7 +199,7 @@ struct let r = Dom.bindings a in List.map (fun (x,v) -> (Dom.singleton x v, b)) r - let threadenter ctx lval f args = + let threadenter ?(multiple=false) ctx lval f args = let g xs x' ys = let ys' = List.map (fun y -> let yr = step ctx.prev_node (ctx.context ()) x' (ThreadEntry (lval, f, args)) (nosync x') in (* threadenter called on before-sync state *) @@ -208,7 +208,7 @@ struct in ys' @ xs in - fold' ctx Spec.threadenter (fun h -> h lval f args) g [] + fold' ctx (Spec.threadenter ~multiple) (fun h -> h lval f args) g [] let threadspawn ctx lval f args fctx = let fd1 = Dom.choose_key (fst fctx.local) in map ctx Spec.threadspawn (fun h -> h lval f args (conv fctx fd1)) From a32513936348d54c724697aba3943c409585f46a Mon Sep 17 00:00:00 2001 From: Michael Schwarz Date: Sun, 24 Sep 2023 17:28:01 +0200 Subject: [PATCH 019/140] Spawn non-unique threads --- src/analyses/base.ml | 14 +++++++------- src/analyses/threadAnalysis.ml | 8 +++++++- src/framework/constraints.ml | 2 +- tests/regression/40-threadid/09-multiple.c | 15 +++++++++++++++ .../regression/40-threadid/10-multiple-thread.c | 16 ++++++++++++++++ 5 files changed, 46 insertions(+), 9 deletions(-) create mode 100644 tests/regression/40-threadid/09-multiple.c create mode 100644 tests/regression/40-threadid/10-multiple-thread.c diff --git a/src/analyses/base.ml b/src/analyses/base.ml index cb29cbc0ab..3b6be2eff8 100644 --- a/src/analyses/base.ml +++ b/src/analyses/base.ml @@ -1902,7 +1902,7 @@ struct - let forkfun (ctx:(D.t, G.t, C.t, V.t) Analyses.ctx) (lv: lval option) (f: varinfo) (args: exp list) : (lval option * varinfo * exp list) list = + let forkfun (ctx:(D.t, G.t, C.t, V.t) Analyses.ctx) (lv: lval option) (f: varinfo) (args: exp list) : (lval option * varinfo * exp list) list * bool = let create_thread lval arg v = try (* try to get function declaration *) @@ -1943,7 +1943,7 @@ struct else start_funvars in - List.filter_map (create_thread (Some (Mem id, NoOffset)) (Some ptc_arg)) start_funvars_with_unknown + List.filter_map (create_thread (Some (Mem id, NoOffset)) (Some ptc_arg)) start_funvars_with_unknown, false end | _, _ when get_bool "sem.unknown_function.spawn" -> (* TODO: Remove sem.unknown_function.spawn check because it is (and should be) really done in LibraryFunctions. @@ -1956,9 +1956,9 @@ struct let deep_flist = collect_invalidate ~deep:true (Analyses.ask_of_ctx ctx) ctx.global ctx.local deep_args in let flist = shallow_flist @ deep_flist in let addrs = List.concat_map AD.to_var_may flist in - if addrs <> [] then M.debug ~category:Analyzer "Spawning functions from unknown function: %a" (d_list ", " CilType.Varinfo.pretty) addrs; - List.filter_map (create_thread None None) addrs - | _, _ -> [] + if addrs <> [] then M.debug ~category:Analyzer "Spawning non-unique functions from unknown function: %a" (d_list ", " CilType.Varinfo.pretty) addrs; + List.filter_map (create_thread None None) addrs, true + | _, _ -> [], false let assert_fn ctx e refine = (* make the state meet the assertion in the rest of the code *) @@ -2024,9 +2024,9 @@ struct let addr = eval_lv (Analyses.ask_of_ctx ctx) ctx.global ctx.local lval in (addr, AD.type_of addr) in - let forks = forkfun ctx lv f args in + let forks, multiple = forkfun ctx lv f args in if M.tracing then if not (List.is_empty forks) then M.tracel "spawn" "Base.special %s: spawning functions %a\n" f.vname (d_list "," CilType.Varinfo.pretty) (List.map BatTuple.Tuple3.second forks); - List.iter (BatTuple.Tuple3.uncurry ctx.spawn) forks; + List.iter (BatTuple.Tuple3.uncurry (ctx.spawn ~multiple)) forks; let st: store = ctx.local in let gs = ctx.global in let desc = LF.find f in diff --git a/src/analyses/threadAnalysis.ml b/src/analyses/threadAnalysis.ml index 26e6702c25..740cca3a53 100644 --- a/src/analyses/threadAnalysis.ml +++ b/src/analyses/threadAnalysis.ml @@ -84,7 +84,13 @@ struct | _ -> Queries.Result.top q let startstate v = D.bot () - let threadenter ?(multiple=false) ctx lval f args = [D.bot ()] + + let threadenter ?(multiple=false) ctx lval f args = + if multiple then + (let tid = ThreadId.get_current_unlift (Analyses.ask_of_ctx ctx) in + ctx.sideg tid (true, TS.bot (), false)); + [D.bot ()] + let threadspawn ctx lval f args fctx = let creator = ThreadId.get_current (Analyses.ask_of_ctx ctx) in let tid = ThreadId.get_current_unlift (Analyses.ask_of_ctx fctx) in diff --git a/src/framework/constraints.ml b/src/framework/constraints.ml index a7683fb6b3..62b8d46efa 100644 --- a/src/framework/constraints.ml +++ b/src/framework/constraints.ml @@ -584,7 +584,7 @@ struct and spawn ?(multiple=false) lval f args = (* TODO: adjust ctx node/edge? *) (* TODO: don't repeat for all paths that spawn same *) - let ds = S.threadenter ctx lval f args in + let ds = S.threadenter ~multiple ctx lval f args in List.iter (fun d -> spawns := (lval, f, args, d) :: !spawns; match Cilfacade.find_varinfo_fundec f with diff --git a/tests/regression/40-threadid/09-multiple.c b/tests/regression/40-threadid/09-multiple.c new file mode 100644 index 0000000000..5510e5ae07 --- /dev/null +++ b/tests/regression/40-threadid/09-multiple.c @@ -0,0 +1,15 @@ +#include +#include + +int myglobal; + +void *t_fun(void *arg) { + myglobal=40; //RACE + return NULL; +} + +int main(void) { + // This should spawn a non-unique thread + unknown(t_fun); + return 0; +} diff --git a/tests/regression/40-threadid/10-multiple-thread.c b/tests/regression/40-threadid/10-multiple-thread.c new file mode 100644 index 0000000000..0024d268ec --- /dev/null +++ b/tests/regression/40-threadid/10-multiple-thread.c @@ -0,0 +1,16 @@ +// PARAM: --set ana.activated[+] thread +#include +#include + +int myglobal; + +void *t_fun(void *arg) { + myglobal=40; //RACE + return NULL; +} + +int main(void) { + // This should spawn a non-unique thread + unknown(t_fun); + return 0; +} From ccaffc592932a7c6ca219aadc28d6f7b74188fcf Mon Sep 17 00:00:00 2001 From: Michael Schwarz Date: Mon, 25 Sep 2023 13:07:31 +0200 Subject: [PATCH 020/140] Turn optional argument into named argument --- src/analyses/abortUnless.ml | 2 +- src/analyses/accessAnalysis.ml | 2 +- src/analyses/activeLongjmp.ml | 2 +- src/analyses/activeSetjmp.ml | 2 +- src/analyses/apron/relationAnalysis.apron.ml | 2 +- src/analyses/base.ml | 2 +- src/analyses/condVars.ml | 2 +- src/analyses/expsplit.ml | 2 +- src/analyses/extractPthread.ml | 2 +- src/analyses/fileUse.ml | 2 +- src/analyses/locksetAnalysis.ml | 2 +- src/analyses/mCP.ml | 2 +- src/analyses/mallocFresh.ml | 2 +- src/analyses/malloc_null.ml | 2 +- src/analyses/modifiedSinceLongjmp.ml | 2 +- src/analyses/mutexTypeAnalysis.ml | 2 +- src/analyses/poisonVariables.ml | 2 +- src/analyses/pthreadSignals.ml | 2 +- src/analyses/region.ml | 2 +- src/analyses/spec.ml | 2 +- src/analyses/stackTrace.ml | 4 ++-- src/analyses/symbLocks.ml | 2 +- src/analyses/taintPartialContexts.ml | 2 +- src/analyses/termination.ml | 2 +- src/analyses/threadAnalysis.ml | 2 +- src/analyses/threadEscape.ml | 2 +- src/analyses/threadFlag.ml | 2 +- src/analyses/threadId.ml | 2 +- src/analyses/threadReturn.ml | 2 +- src/analyses/tmpSpecial.ml | 2 +- src/analyses/tutorials/taint.ml | 2 +- src/analyses/tutorials/unitAnalysis.ml | 2 +- src/analyses/uninit.ml | 2 +- src/analyses/useAfterFree.ml | 2 +- src/analyses/varEq.ml | 2 +- src/analyses/vla.ml | 2 +- src/analyses/wrapperFunctionAnalysis.ml | 2 +- src/framework/analyses.ml | 4 ++-- src/framework/constraints.ml | 20 ++++++++++---------- src/framework/control.ml | 2 +- src/util/wideningTokens.ml | 2 +- src/witness/observerAnalysis.ml | 2 +- src/witness/witnessConstraints.ml | 2 +- 43 files changed, 54 insertions(+), 54 deletions(-) diff --git a/src/analyses/abortUnless.ml b/src/analyses/abortUnless.ml index 1c77803c7e..5c24e61f7c 100644 --- a/src/analyses/abortUnless.ml +++ b/src/analyses/abortUnless.ml @@ -65,7 +65,7 @@ struct false let startstate v = false - let threadenter ?(multiple=false) ctx lval f args = [false] + let threadenter ctx ~multiple lval f args = [false] let threadspawn ctx lval f args fctx = false let exitstate v = false end diff --git a/src/analyses/accessAnalysis.ml b/src/analyses/accessAnalysis.ml index bd1ca528a7..f0025c2f1c 100644 --- a/src/analyses/accessAnalysis.ml +++ b/src/analyses/accessAnalysis.ml @@ -54,7 +54,7 @@ struct (** We just lift start state, global and dependency functions: *) let startstate v = () - let threadenter ?(multiple=false) ctx lval f args = [()] + let threadenter ctx ~multiple lval f args = [()] let exitstate v = () let context fd d = () diff --git a/src/analyses/activeLongjmp.ml b/src/analyses/activeLongjmp.ml index 43da8c6512..9baa601ddc 100644 --- a/src/analyses/activeLongjmp.ml +++ b/src/analyses/activeLongjmp.ml @@ -26,7 +26,7 @@ struct (* Initial values don't really matter: overwritten at longjmp call. *) let startstate v = D.bot () - let threadenter ?(multiple=false) ctx lval f args = [D.bot ()] + let threadenter ctx ~multiple lval f args = [D.bot ()] let exitstate v = D.top () let query ctx (type a) (q: a Queries.t): a Queries.result = diff --git a/src/analyses/activeSetjmp.ml b/src/analyses/activeSetjmp.ml index a69bf4db95..be13489993 100644 --- a/src/analyses/activeSetjmp.ml +++ b/src/analyses/activeSetjmp.ml @@ -25,7 +25,7 @@ struct | _ -> ctx.local let startstate v = D.bot () - let threadenter ?(multiple=false) ctx lval f args = [D.bot ()] + let threadenter ctx ~multiple lval f args = [D.bot ()] let exitstate v = D.top () let query ctx (type a) (q: a Queries.t): a Queries.result = diff --git a/src/analyses/apron/relationAnalysis.apron.ml b/src/analyses/apron/relationAnalysis.apron.ml index d56064a42f..c232ccae9b 100644 --- a/src/analyses/apron/relationAnalysis.apron.ml +++ b/src/analyses/apron/relationAnalysis.apron.ml @@ -647,7 +647,7 @@ struct (* Thread transfer functions. *) - let threadenter ?(multiple=false) ctx lval f args = + let threadenter ctx ~multiple lval f args = let st = ctx.local in match Cilfacade.find_varinfo_fundec f with | fd -> diff --git a/src/analyses/base.ml b/src/analyses/base.ml index 3b6be2eff8..e824fac013 100644 --- a/src/analyses/base.ml +++ b/src/analyses/base.ml @@ -2503,7 +2503,7 @@ struct in combine_one ctx.local after - let threadenter ?(multiple=false) ctx (lval: lval option) (f: varinfo) (args: exp list): D.t list = + let threadenter ctx ~multiple (lval: lval option) (f: varinfo) (args: exp list): D.t list = match Cilfacade.find_varinfo_fundec f with | fd -> [make_entry ~thread:true ctx fd args] diff --git a/src/analyses/condVars.ml b/src/analyses/condVars.ml index 3a2cc5798d..820ff69efa 100644 --- a/src/analyses/condVars.ml +++ b/src/analyses/condVars.ml @@ -155,7 +155,7 @@ struct ctx.local let startstate v = D.bot () - let threadenter ?(multiple=false) ctx lval f args = [D.bot ()] + let threadenter ctx ~multiple lval f args = [D.bot ()] let threadspawn ctx lval f args fctx = ctx.local let exitstate v = D.bot () end diff --git a/src/analyses/expsplit.ml b/src/analyses/expsplit.ml index 9c610a96bf..141a04283b 100644 --- a/src/analyses/expsplit.ml +++ b/src/analyses/expsplit.ml @@ -84,7 +84,7 @@ struct in emit_splits ctx d - let threadenter ?(multiple=false) ctx lval f args = [ctx.local] + let threadenter ctx ~multiple lval f args = [ctx.local] let threadspawn ctx lval f args fctx = emit_splits_ctx ctx diff --git a/src/analyses/extractPthread.ml b/src/analyses/extractPthread.ml index 591704cc70..f72f72c1fe 100644 --- a/src/analyses/extractPthread.ml +++ b/src/analyses/extractPthread.ml @@ -1238,7 +1238,7 @@ module Spec : Analyses.MCPSpec = struct (Ctx.top ()) - let threadenter ?(multiple=false) ctx lval f args = + let threadenter ctx ~multiple lval f args = let d : D.t = ctx.local in let tasks = ctx.global tasks_var in (* TODO: optimize finding *) diff --git a/src/analyses/fileUse.ml b/src/analyses/fileUse.ml index b12953c71c..b8e7fd78f5 100644 --- a/src/analyses/fileUse.ml +++ b/src/analyses/fileUse.ml @@ -287,7 +287,7 @@ struct | _ -> m let startstate v = D.bot () - let threadenter ?(multiple=false) ctx lval f args = [D.bot ()] + let threadenter ctx ~multiple lval f args = [D.bot ()] let threadspawn ctx lval f args fctx = ctx.local let exitstate v = D.bot () end diff --git a/src/analyses/locksetAnalysis.ml b/src/analyses/locksetAnalysis.ml index 56fe960a47..6a816b9e6c 100644 --- a/src/analyses/locksetAnalysis.ml +++ b/src/analyses/locksetAnalysis.ml @@ -18,7 +18,7 @@ struct module C = D let startstate v = D.empty () - let threadenter ?(multiple=false) ctx lval f args = [D.empty ()] + let threadenter ctx ~multiple lval f args = [D.empty ()] let exitstate v = D.empty () end diff --git a/src/analyses/mCP.ml b/src/analyses/mCP.ml index e305e9c7f6..5259bdb6c7 100644 --- a/src/analyses/mCP.ml +++ b/src/analyses/mCP.ml @@ -565,7 +565,7 @@ struct let d = do_emits ctx !emits d q in if q then raise Deadcode else d - let threadenter ?(multiple=false) (ctx:(D.t, G.t, C.t, V.t) ctx) lval f a = + let threadenter (ctx:(D.t, G.t, C.t, V.t) ctx) ~multiple lval f a = let sides = ref [] in let emits = ref [] in let ctx'' = outer_ctx "threadenter" ~sides ~emits ctx in diff --git a/src/analyses/mallocFresh.ml b/src/analyses/mallocFresh.ml index 861e4958bd..e171ad4ea1 100644 --- a/src/analyses/mallocFresh.ml +++ b/src/analyses/mallocFresh.ml @@ -52,7 +52,7 @@ struct | None -> ctx.local | Some lval -> assign_lval (Analyses.ask_of_ctx ctx) lval ctx.local - let threadenter ?(multiple=false) ctx lval f args = + let threadenter ctx ~multiple lval f args = [D.empty ()] let threadspawn ctx lval f args fctx = diff --git a/src/analyses/malloc_null.ml b/src/analyses/malloc_null.ml index 2d90112636..41c251dfce 100644 --- a/src/analyses/malloc_null.ml +++ b/src/analyses/malloc_null.ml @@ -215,7 +215,7 @@ struct let name () = "malloc_null" let startstate v = D.empty () - let threadenter ?(multiple=false) ctx lval f args = [D.empty ()] + let threadenter ctx ~multiple lval f args = [D.empty ()] let threadspawn ctx lval f args fctx = ctx.local let exitstate v = D.empty () diff --git a/src/analyses/modifiedSinceLongjmp.ml b/src/analyses/modifiedSinceLongjmp.ml index d9c8f5102c..7da0030b9a 100644 --- a/src/analyses/modifiedSinceLongjmp.ml +++ b/src/analyses/modifiedSinceLongjmp.ml @@ -63,7 +63,7 @@ struct ctx.local let startstate v = D.bot () - let threadenter ?(multiple=false) ctx lval f args = [D.bot ()] + let threadenter ctx ~multiple lval f args = [D.bot ()] let exitstate v = D.top () let query ctx (type a) (q: a Queries.t): a Queries.result = diff --git a/src/analyses/mutexTypeAnalysis.ml b/src/analyses/mutexTypeAnalysis.ml index 7051173bd0..66e60aede1 100644 --- a/src/analyses/mutexTypeAnalysis.ml +++ b/src/analyses/mutexTypeAnalysis.ml @@ -65,7 +65,7 @@ struct | _ -> ctx.local let startstate v = D.bot () - let threadenter ?(multiple=false) ctx lval f args = [D.top ()] + let threadenter ctx ~multiple lval f args = [D.top ()] let threadspawn ctx lval f args fctx = ctx.local let exitstate v = D.top () diff --git a/src/analyses/poisonVariables.ml b/src/analyses/poisonVariables.ml index 8c79626cc9..87dddd1e54 100644 --- a/src/analyses/poisonVariables.ml +++ b/src/analyses/poisonVariables.ml @@ -61,7 +61,7 @@ struct VS.join au ctx.local let startstate v = D.bot () - let threadenter ?(multiple=false) ctx lval f args = [D.bot ()] + let threadenter ctx ~multiple lval f args = [D.bot ()] let exitstate v = D.top () let event ctx e octx = diff --git a/src/analyses/pthreadSignals.ml b/src/analyses/pthreadSignals.ml index 83455965ec..70f1624922 100644 --- a/src/analyses/pthreadSignals.ml +++ b/src/analyses/pthreadSignals.ml @@ -73,7 +73,7 @@ struct | _ -> ctx.local let startstate v = Signals.empty () - let threadenter ?(multiple=false) ctx lval f args = [ctx.local] + let threadenter ctx ~multiple lval f args = [ctx.local] let exitstate v = Signals.empty () end diff --git a/src/analyses/region.ml b/src/analyses/region.ml index 9d68221fcd..86cad5684b 100644 --- a/src/analyses/region.ml +++ b/src/analyses/region.ml @@ -175,7 +175,7 @@ struct let startstate v = `Lifted (RegMap.bot ()) - let threadenter ?(multiple=false) ctx lval f args = + let threadenter ctx ~multiple lval f args = [`Lifted (RegMap.bot ())] let threadspawn ctx lval f args fctx = ctx.local diff --git a/src/analyses/spec.ml b/src/analyses/spec.ml index e5434eb264..c44edd6c87 100644 --- a/src/analyses/spec.ml +++ b/src/analyses/spec.ml @@ -487,7 +487,7 @@ struct let startstate v = D.bot () - let threadenter ?(multiple=false) ctx lval f args = [D.bot ()] + let threadenter ctx ~multiple lval f args = [D.bot ()] let threadspawn ctx lval f args fctx = ctx.local let exitstate v = D.bot () end diff --git a/src/analyses/stackTrace.ml b/src/analyses/stackTrace.ml index 3d70c50856..3c3bd56640 100644 --- a/src/analyses/stackTrace.ml +++ b/src/analyses/stackTrace.ml @@ -21,7 +21,7 @@ struct ctx.local (* keep local as opposed to IdentitySpec *) let startstate v = D.bot () - let threadenter ?(multiple=false) ctx lval f args = [D.bot ()] + let threadenter ctx ~multiple lval f args = [D.bot ()] let exitstate v = D.top () end @@ -45,7 +45,7 @@ struct let startstate v = D.bot () let exitstate v = D.top () - let threadenter ?(multiple=false) ctx lval f args = + let threadenter ctx ~multiple lval f args = [D.push !Tracing.current_loc ctx.local] end diff --git a/src/analyses/symbLocks.ml b/src/analyses/symbLocks.ml index b99ef93039..32be32f73d 100644 --- a/src/analyses/symbLocks.ml +++ b/src/analyses/symbLocks.ml @@ -29,7 +29,7 @@ struct let name () = "symb_locks" let startstate v = D.top () - let threadenter ?(multiple=false) ctx lval f args = [D.top ()] + let threadenter ctx ~multiple lval f args = [D.top ()] let threadspawn ctx lval f args fctx = ctx.local let exitstate v = D.top () diff --git a/src/analyses/taintPartialContexts.ml b/src/analyses/taintPartialContexts.ml index 25e981dcbf..b45ea54877 100644 --- a/src/analyses/taintPartialContexts.ml +++ b/src/analyses/taintPartialContexts.ml @@ -101,7 +101,7 @@ struct d let startstate v = D.bot () - let threadenter ?(multiple=false) ctx lval f args = + let threadenter ctx ~multiple lval f args = [D.bot ()] let threadspawn ctx lval f args fctx = match lval with diff --git a/src/analyses/termination.ml b/src/analyses/termination.ml index 5e5e0d36f1..0563730fb2 100644 --- a/src/analyses/termination.ml +++ b/src/analyses/termination.ml @@ -217,7 +217,7 @@ struct (* | _ -> ctx.local *) let startstate v = D.bot () - let threadenter ?(multiple=false) ctx lval f args = [D.bot ()] + let threadenter ctx ~multiple lval f args = [D.bot ()] let exitstate v = D.bot () end diff --git a/src/analyses/threadAnalysis.ml b/src/analyses/threadAnalysis.ml index 740cca3a53..ff4b4d5c63 100644 --- a/src/analyses/threadAnalysis.ml +++ b/src/analyses/threadAnalysis.ml @@ -85,7 +85,7 @@ struct let startstate v = D.bot () - let threadenter ?(multiple=false) ctx lval f args = + let threadenter ctx ~multiple lval f args = if multiple then (let tid = ThreadId.get_current_unlift (Analyses.ask_of_ctx ctx) in ctx.sideg tid (true, TS.bot (), false)); diff --git a/src/analyses/threadEscape.ml b/src/analyses/threadEscape.ml index 0674ebf3d1..0948a3976d 100644 --- a/src/analyses/threadEscape.ml +++ b/src/analyses/threadEscape.ml @@ -150,7 +150,7 @@ struct let startstate v = D.bot () let exitstate v = D.bot () - let threadenter ?(multiple=false) ctx lval f args = + let threadenter ctx ~multiple lval f args = [D.bot ()] let threadspawn ctx lval f args fctx = diff --git a/src/analyses/threadFlag.ml b/src/analyses/threadFlag.ml index f3b132918a..81e05af679 100644 --- a/src/analyses/threadFlag.ml +++ b/src/analyses/threadFlag.ml @@ -58,7 +58,7 @@ struct let access ctx _ = is_currently_multi (Analyses.ask_of_ctx ctx) - let threadenter ?(multiple=false) ctx lval f args = + let threadenter ctx ~multiple lval f args = if not (has_ever_been_multi (Analyses.ask_of_ctx ctx)) then ctx.emit Events.EnterMultiThreaded; [create_tid f] diff --git a/src/analyses/threadId.ml b/src/analyses/threadId.ml index f1de1dfdcb..a9f3fa35f7 100644 --- a/src/analyses/threadId.ml +++ b/src/analyses/threadId.ml @@ -133,7 +133,7 @@ struct | `Lifted node, count -> node, Some count | (`Bot | `Top), _ -> ctx.prev_node, None - let threadenter ?(multiple=false) ctx lval f args:D.t list = + let threadenter ctx ~multiple lval f args:D.t list = let n, i = indexed_node_for_ctx ctx in let+ tid = create_tid ~multiple ctx.local (n, i) f in (`Lifted (f, n, i), tid, (TD.bot (), TD.bot ())) diff --git a/src/analyses/threadReturn.ml b/src/analyses/threadReturn.ml index 176a4d3465..0aed06851a 100644 --- a/src/analyses/threadReturn.ml +++ b/src/analyses/threadReturn.ml @@ -28,7 +28,7 @@ struct ctx.local (* keep local as opposed to IdentitySpec *) let startstate v = true - let threadenter ?(multiple=false) ctx lval f args = [true] + let threadenter ctx ~multiple lval f args = [true] let exitstate v = D.top () let query (ctx: (D.t, _, _, _) ctx) (type a) (x: a Queries.t): a Queries.result = diff --git a/src/analyses/tmpSpecial.ml b/src/analyses/tmpSpecial.ml index f3d092e59e..046345e627 100644 --- a/src/analyses/tmpSpecial.ml +++ b/src/analyses/tmpSpecial.ml @@ -88,7 +88,7 @@ struct | _ -> Queries.Result.top q let startstate v = D.bot () - let threadenter ?(multiple=false) ctx lval f args = [D.bot ()] + let threadenter ctx ~multiple lval f args = [D.bot ()] let threadspawn ctx lval f args fctx = ctx.local let exitstate v = D.bot () end diff --git a/src/analyses/tutorials/taint.ml b/src/analyses/tutorials/taint.ml index 166ce2c3f6..7fc3fd7343 100644 --- a/src/analyses/tutorials/taint.ml +++ b/src/analyses/tutorials/taint.ml @@ -129,7 +129,7 @@ struct (* You may leave these alone *) let startstate v = D.bot () - let threadenter ?(multiple=false) ctx lval f args = [D.top ()] + let threadenter ctx ~multiple lval f args = [D.top ()] let threadspawn ctx lval f args fctx = ctx.local let exitstate v = D.top () end diff --git a/src/analyses/tutorials/unitAnalysis.ml b/src/analyses/tutorials/unitAnalysis.ml index b5fb4d6367..3ecddc2bc0 100644 --- a/src/analyses/tutorials/unitAnalysis.ml +++ b/src/analyses/tutorials/unitAnalysis.ml @@ -39,7 +39,7 @@ struct ctx.local let startstate v = D.bot () - let threadenter ?(multiple=false) ctx lval f args = [D.top ()] + let threadenter ctx ~multiple lval f args = [D.top ()] let threadspawn ctx lval f args fctx = ctx.local let exitstate v = D.top () end diff --git a/src/analyses/uninit.ml b/src/analyses/uninit.ml index abdcd67aaa..2b388d1190 100644 --- a/src/analyses/uninit.ml +++ b/src/analyses/uninit.ml @@ -25,7 +25,7 @@ struct let name () = "uninit" let startstate v : D.t = D.empty () - let threadenter ?(multiple=false) ctx lval f args = [D.empty ()] + let threadenter ctx ~multiple lval f args = [D.empty ()] let threadspawn ctx lval f args fctx = ctx.local let exitstate v : D.t = D.empty () diff --git a/src/analyses/useAfterFree.ml b/src/analyses/useAfterFree.ml index 6033c689e1..0c7a46c35f 100644 --- a/src/analyses/useAfterFree.ml +++ b/src/analyses/useAfterFree.ml @@ -196,7 +196,7 @@ struct end | _ -> state - let threadenter ?(multiple=false) ctx lval f args = [ctx.local] + let threadenter ctx ~multiple lval f args = [ctx.local] let threadspawn ctx lval f args fctx = ctx.local let startstate v = D.bot () diff --git a/src/analyses/varEq.ml b/src/analyses/varEq.ml index 7bd3453b8a..3aaef95265 100644 --- a/src/analyses/varEq.ml +++ b/src/analyses/varEq.ml @@ -43,7 +43,7 @@ struct let name () = "var_eq" let startstate v = D.top () - let threadenter ?(multiple=false) ctx lval f args = [D.top ()] + let threadenter ctx ~multiple lval f args = [D.top ()] let threadspawn ctx lval f args fctx = ctx.local let exitstate v = D.top () diff --git a/src/analyses/vla.ml b/src/analyses/vla.ml index 8bd0168de0..665612aa99 100644 --- a/src/analyses/vla.ml +++ b/src/analyses/vla.ml @@ -33,7 +33,7 @@ struct ctx.local || Cilfacade.isVLAType v.vtype let startstate v = D.bot () - let threadenter ?(multiple=false) ctx lval f args = [D.top ()] + let threadenter ctx ~multiple lval f args = [D.top ()] let exitstate v = D.top () end diff --git a/src/analyses/wrapperFunctionAnalysis.ml b/src/analyses/wrapperFunctionAnalysis.ml index 89242e044e..a1bec69a8c 100644 --- a/src/analyses/wrapperFunctionAnalysis.ml +++ b/src/analyses/wrapperFunctionAnalysis.ml @@ -87,7 +87,7 @@ struct let startstate v = D.bot () - let threadenter ?(multiple=false) ctx lval f args = + let threadenter ctx ~multiple lval f args = (* The new thread receives a fresh counter *) [D.bot ()] diff --git a/src/framework/analyses.ml b/src/framework/analyses.ml index 54a3a18f1a..3bb88a6ead 100644 --- a/src/framework/analyses.ml +++ b/src/framework/analyses.ml @@ -444,7 +444,7 @@ sig val paths_as_set : (D.t, G.t, C.t, V.t) ctx -> D.t list (** Returns initial state for created thread. *) - val threadenter : ?multiple:bool -> (D.t, G.t, C.t, V.t) ctx -> lval option -> varinfo -> exp list -> D.t list + val threadenter : (D.t, G.t, C.t, V.t) ctx -> multiple:bool -> lval option -> varinfo -> exp list -> D.t list (** Updates the local state of the creator thread using initial state of created thread. *) val threadspawn : (D.t, G.t, C.t, V.t) ctx -> lval option -> varinfo -> exp list -> (D.t, G.t, C.t, V.t) ctx -> D.t @@ -696,7 +696,7 @@ struct let special ctx (lval: lval option) (f:varinfo) (arglist:exp list) = ctx.local - let threadenter ?(multiple=false) ctx lval f args = [ctx.local] + let threadenter ctx ~multiple lval f args = [ctx.local] let threadspawn ctx lval f args fctx = ctx.local end diff --git a/src/framework/constraints.ml b/src/framework/constraints.ml index 62b8d46efa..ed492f4237 100644 --- a/src/framework/constraints.ml +++ b/src/framework/constraints.ml @@ -83,8 +83,8 @@ struct let combine_assign ctx r fe f args fc es f_ask = D.lift @@ S.combine_assign (conv ctx) r fe f args fc (D.unlift es) f_ask - let threadenter ?(multiple=false) ctx lval f args = - List.map D.lift @@ (S.threadenter ~multiple) (conv ctx) lval f args + let threadenter ctx ~multiple lval f args = + List.map D.lift @@ S.threadenter (conv ctx) ~multiple lval f args let threadspawn ctx lval f args fctx = D.lift @@ S.threadspawn (conv ctx) lval f args (conv fctx) @@ -167,8 +167,8 @@ struct let combine_assign ctx r fe f args fc es f_ask = S.combine_assign (conv ctx) r fe f args (Option.map C.unlift fc) es f_ask - let threadenter ?(multiple=false) ctx lval f args = - S.threadenter ~multiple (conv ctx) lval f args + let threadenter ctx ~multiple lval f args = + S.threadenter (conv ctx) ~multiple lval f args let threadspawn ctx lval f args fctx = S.threadspawn (conv ctx) lval f args (conv fctx) @@ -249,7 +249,7 @@ struct let combine_env' ctx r fe f args fc es f_ask = lift_fun ctx (lift ctx) S.combine_env (fun p -> p r fe f args fc (fst es) f_ask) let combine_assign' ctx r fe f args fc es f_ask = lift_fun ctx (lift ctx) S.combine_assign (fun p -> p r fe f args fc (fst es) f_ask) - let threadenter ?(multiple=false) ctx lval f args = lift_fun ctx (List.map lift_start_level) (S.threadenter ~multiple) ((|>) args % (|>) f % (|>) lval) + let threadenter ctx ~multiple lval f args = lift_fun ctx (List.map lift_start_level) (S.threadenter ~multiple) ((|>) args % (|>) f % (|>) lval) let threadspawn ctx lval f args fctx = lift_fun ctx (lift ctx) S.threadspawn ((|>) (conv fctx) % (|>) args % (|>) f % (|>) lval) let leq0 = function @@ -394,7 +394,7 @@ struct let event ctx e octx = lift_fun ctx S.event ((|>) (conv octx) % (|>) e) - let threadenter ?(multiple=false) ctx lval f args = S.threadenter ~multiple (conv ctx) lval f args |> List.map (fun d -> (d, snd ctx.local)) + let threadenter ctx ~multiple lval f args = S.threadenter (conv ctx) ~multiple lval f args |> List.map (fun d -> (d, snd ctx.local)) let threadspawn ctx lval f args fctx = lift_fun ctx S.threadspawn ((|>) (conv fctx) % (|>) args % (|>) f % (|>) lval) let enter ctx r f args = @@ -485,7 +485,7 @@ struct let combine_env ctx r fe f args fc es f_ask = lift_fun ctx D.lift S.combine_env (fun p -> p r fe f args fc (D.unlift es) f_ask) `Bot let combine_assign ctx r fe f args fc es f_ask = lift_fun ctx D.lift S.combine_assign (fun p -> p r fe f args fc (D.unlift es) f_ask) `Bot - let threadenter ?(multiple=false) ctx lval f args = lift_fun ctx (List.map D.lift) (S.threadenter ~multiple) ((|>) args % (|>) f % (|>) lval) [] + let threadenter ctx ~multiple lval f args = lift_fun ctx (List.map D.lift) (S.threadenter ~multiple) ((|>) args % (|>) f % (|>) lval) [] let threadspawn ctx lval f args fctx = lift_fun ctx D.lift S.threadspawn ((|>) (conv fctx) % (|>) args % (|>) f % (|>) lval) `Bot let event (ctx:(D.t,G.t,C.t,V.t) ctx) (e:Events.t) (octx:(D.t,G.t,C.t,V.t) ctx):D.t = lift_fun ctx D.lift S.event ((|>) (conv octx) % (|>) e) `Bot @@ -1262,7 +1262,7 @@ struct let fd1 = D.choose octx.local in map ctx Spec.event (fun h -> h e (conv octx fd1)) - let threadenter ?(multiple=false) ctx lval f args = + let threadenter ctx ~multiple lval f args = let g xs ys = (List.map (fun y -> D.singleton y) ys) @ xs in fold' ctx (Spec.threadenter ~multiple) (fun h -> h lval f args) g [] @@ -1449,7 +1449,7 @@ struct let combine_env ctx = S.combine_env (conv ctx) let combine_assign ctx = S.combine_assign (conv ctx) let special ctx = S.special (conv ctx) - let threadenter ?(multiple=false) ctx = S.threadenter ~multiple (conv ctx) + let threadenter ctx = S.threadenter (conv ctx) let threadspawn ctx lv f args fctx = S.threadspawn (conv ctx) lv f args (conv fctx) let sync ctx = S.sync (conv ctx) let skip ctx = S.skip (conv ctx) @@ -1685,7 +1685,7 @@ struct List.iter handle_path (S.paths_as_set conv_ctx); S.D.bot () | _ -> S.special conv_ctx lv f args - let threadenter ?(multiple=false) ctx = S.threadenter ~multiple (conv ctx) + let threadenter ctx = S.threadenter (conv ctx) let threadspawn ctx lv f args fctx = S.threadspawn (conv ctx) lv f args (conv fctx) let sync ctx = S.sync (conv ctx) let skip ctx = S.skip (conv ctx) diff --git a/src/framework/control.ml b/src/framework/control.ml index 72890be4b4..3ec428014b 100644 --- a/src/framework/control.ml +++ b/src/framework/control.ml @@ -423,7 +423,7 @@ struct } in (* TODO: don't hd *) - List.hd (Spec.threadenter ctx None v []) + List.hd (Spec.threadenter ctx ~multiple:false None v []) (* TODO: do threadspawn to mainfuns? *) in let prestartstate = Spec.startstate MyCFG.dummy_func.svar in (* like in do_extern_inits *) diff --git a/src/util/wideningTokens.ml b/src/util/wideningTokens.ml index c88f3f00c1..73c160e3bb 100644 --- a/src/util/wideningTokens.ml +++ b/src/util/wideningTokens.ml @@ -179,7 +179,7 @@ struct let combine_env ctx r fe f args fc es f_ask = lift_fun ctx lift' S.combine_env (fun p -> p r fe f args fc (D.unlift es) f_ask) (* TODO: use tokens from es *) let combine_assign ctx r fe f args fc es f_ask = lift_fun ctx lift' S.combine_assign (fun p -> p r fe f args fc (D.unlift es) f_ask) (* TODO: use tokens from es *) - let threadenter ?(multiple=false) ctx lval f args = lift_fun ctx (fun l ts -> List.map (Fun.flip lift' ts) l) (S.threadenter ~multiple) ((|>) args % (|>) f % (|>) lval ) + let threadenter ctx ~multiple lval f args = lift_fun ctx (fun l ts -> List.map (Fun.flip lift' ts) l) (S.threadenter ~multiple) ((|>) args % (|>) f % (|>) lval ) let threadspawn ctx lval f args fctx = lift_fun ctx lift' S.threadspawn ((|>) (conv fctx) % (|>) args % (|>) f % (|>) lval) let event ctx e octx = lift_fun ctx lift' S.event ((|>) (conv octx) % (|>) e) end diff --git a/src/witness/observerAnalysis.ml b/src/witness/observerAnalysis.ml index 3c702d199f..45a547c471 100644 --- a/src/witness/observerAnalysis.ml +++ b/src/witness/observerAnalysis.ml @@ -76,7 +76,7 @@ struct step_ctx ctx let startstate v = `Lifted Automaton.initial - let threadenter ?(multiple=false) ctx lval f args = [D.top ()] + let threadenter ctx ~multiple lval f args = [D.top ()] let threadspawn ctx lval f args fctx = ctx.local let exitstate v = D.top () end diff --git a/src/witness/witnessConstraints.ml b/src/witness/witnessConstraints.ml index ad32713fa8..1bf6294020 100644 --- a/src/witness/witnessConstraints.ml +++ b/src/witness/witnessConstraints.ml @@ -199,7 +199,7 @@ struct let r = Dom.bindings a in List.map (fun (x,v) -> (Dom.singleton x v, b)) r - let threadenter ?(multiple=false) ctx lval f args = + let threadenter ctx ~multiple lval f args = let g xs x' ys = let ys' = List.map (fun y -> let yr = step ctx.prev_node (ctx.context ()) x' (ThreadEntry (lval, f, args)) (nosync x') in (* threadenter called on before-sync state *) From c4bf1ccbeb23c2f8248fa755a8f4949efbe328e9 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Tue, 26 Sep 2023 15:16:51 +0300 Subject: [PATCH 021/140] Add some library functions for zstd --- src/analyses/libraryFunctions.ml | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/analyses/libraryFunctions.ml b/src/analyses/libraryFunctions.ml index 137a3103a5..9ee9dc8c9d 100644 --- a/src/analyses/libraryFunctions.ml +++ b/src/analyses/libraryFunctions.ml @@ -209,6 +209,7 @@ let posix_descs_list: (string * LibraryDesc.t) list = LibraryDsl.[ ("strnlen", unknown [drop "s" [r]; drop "maxlen" []]); ("chmod", unknown [drop "pathname" [r]; drop "mode" []]); ("fchmod", unknown [drop "fd" []; drop "mode" []]); + ("chown", unknown [drop "pathname" [r]; drop "owner" []; drop "group" []]); ("fchown", unknown [drop "fd" []; drop "owner" []; drop "group" []]); ("lchown", unknown [drop "pathname" [r]; drop "owner" []; drop "group" []]); ("clock_gettime", unknown [drop "clockid" []; drop "tp" [w]]); @@ -245,6 +246,7 @@ let posix_descs_list: (string * LibraryDesc.t) list = LibraryDsl.[ ("timer_settime", unknown [drop "timerid" []; drop "flags" []; drop "new_value" [r_deep]; drop "old_value" [w_deep]]); ("timer_gettime", unknown [drop "timerid" []; drop "curr_value" [w_deep]]); ("timer_getoverrun", unknown [drop "timerid" []]); + ("fstat", unknown [drop "fd" []; drop "statbuf" [w]]); ("lstat", unknown [drop "pathname" [r]; drop "statbuf" [w]]); ("getpwnam", unknown [drop "name" [r]]); ("chdir", unknown [drop "path" [r]]); @@ -833,12 +835,23 @@ let zlib_descs_list: (string * LibraryDesc.t) list = LibraryDsl.[ ("inflateInit2", unknown [drop "strm" [r_deep; w_deep]; drop "windowBits" []]); ("inflateInit2_", unknown [drop "strm" [r_deep; w_deep]; drop "windowBits" []; drop "version" [r]; drop "stream_size" []]); ("inflateEnd", unknown [drop "strm" [f_deep]]); + ("deflate", unknown [drop "strm" [r_deep; w_deep]; drop "flush" []]); + ("deflateInit2", unknown [drop "strm" [r_deep; w_deep]; drop "level" []; drop "method" []; drop "windowBits" []; drop "memLevel" []; drop "strategy" []]); + ("deflateInit2_", unknown [drop "strm" [r_deep; w_deep]; drop "level" []; drop "method" []; drop "windowBits" []; drop "memLevel" []; drop "strategy" []; drop "version" [r]; drop "stream_size" []]); + ("deflateEnd", unknown [drop "strm" [f_deep]]); + ("zlibVersion", unknown []); ] let liblzma_descs_list: (string * LibraryDesc.t) list = LibraryDsl.[ ("lzma_code", unknown [drop "strm" [r_deep; w_deep]; drop "action" []]); ("lzma_auto_decoder", unknown [drop "strm" [r_deep; w_deep]; drop "memlimit" []; drop "flags" []]); + ("lzma_alone_decoder", unknown [drop "strm" [r_deep; w_deep]; drop "memlimit" []]); + ("lzma_stream_decoder", unknown [drop "strm" [r_deep; w_deep]; drop "memlimit" []; drop "flags" []]); + ("lzma_alone_encoder", unknown [drop "strm" [r_deep; w_deep]; drop "options" [r_deep]]); + ("lzma_easy_encoder", unknown [drop "strm" [r_deep; w_deep]; drop "preset" []; drop "check" []]); ("lzma_end", unknown [drop "strm" [r_deep; w_deep; f_deep]]); + ("lzma_version_string", unknown []); + ("lzma_lzma_preset", unknown [drop "options" [w_deep]; drop "preset" []]); ] let libraries = Hashtbl.of_list [ From 7ebddbc89f20e16927eafb6abafa3e79abde2fe8 Mon Sep 17 00:00:00 2001 From: Michael Schwarz Date: Thu, 28 Sep 2023 13:48:47 +0200 Subject: [PATCH 022/140] Also pass to threadspawn for history TID + uniqueness --- src/analyses/abortUnless.ml | 2 +- src/analyses/accessAnalysis.ml | 2 +- src/analyses/apron/relationAnalysis.apron.ml | 2 +- src/analyses/base.ml | 2 +- src/analyses/condVars.ml | 2 +- src/analyses/expsplit.ml | 2 +- src/analyses/extractPthread.ml | 2 +- src/analyses/fileUse.ml | 2 +- src/analyses/mCP.ml | 4 +- src/analyses/mallocFresh.ml | 2 +- src/analyses/malloc_null.ml | 2 +- src/analyses/mutexTypeAnalysis.ml | 2 +- src/analyses/region.ml | 2 +- src/analyses/spec.ml | 2 +- src/analyses/symbLocks.ml | 2 +- src/analyses/taintPartialContexts.ml | 2 +- src/analyses/threadAnalysis.ml | 2 +- src/analyses/threadEscape.ml | 2 +- src/analyses/threadFlag.ml | 2 +- src/analyses/threadId.ml | 8 +-- src/analyses/threadJoins.ml | 2 +- src/analyses/tmpSpecial.ml | 2 +- src/analyses/tutorials/taint.ml | 2 +- src/analyses/tutorials/unitAnalysis.ml | 2 +- src/analyses/uninit.ml | 2 +- src/analyses/useAfterFree.ml | 2 +- src/analyses/varEq.ml | 2 +- src/cdomains/threadIdDomain.ml | 55 ++++++++++---------- src/framework/analyses.ml | 4 +- src/framework/constraints.ml | 30 +++++------ src/util/wideningTokens.ml | 2 +- src/witness/observerAnalysis.ml | 2 +- src/witness/witnessConstraints.ml | 4 +- 33 files changed, 80 insertions(+), 79 deletions(-) diff --git a/src/analyses/abortUnless.ml b/src/analyses/abortUnless.ml index 5c24e61f7c..ee4db69820 100644 --- a/src/analyses/abortUnless.ml +++ b/src/analyses/abortUnless.ml @@ -66,7 +66,7 @@ struct let startstate v = false let threadenter ctx ~multiple lval f args = [false] - let threadspawn ctx lval f args fctx = false + let threadspawn ctx ~multiple lval f args fctx = false let exitstate v = false end diff --git a/src/analyses/accessAnalysis.ml b/src/analyses/accessAnalysis.ml index f0025c2f1c..b181a1c70e 100644 --- a/src/analyses/accessAnalysis.ml +++ b/src/analyses/accessAnalysis.ml @@ -121,7 +121,7 @@ struct ctx.local - let threadspawn ctx lval f args fctx = + let threadspawn ctx ~multiple lval f args fctx = (* must explicitly access thread ID lval because special to pthread_create doesn't if singlethreaded before *) begin match lval with | None -> () diff --git a/src/analyses/apron/relationAnalysis.apron.ml b/src/analyses/apron/relationAnalysis.apron.ml index c232ccae9b..13f549fc44 100644 --- a/src/analyses/apron/relationAnalysis.apron.ml +++ b/src/analyses/apron/relationAnalysis.apron.ml @@ -665,7 +665,7 @@ struct (* TODO: do something like base? *) failwith "relation.threadenter: unknown function" - let threadspawn ctx lval f args fctx = + let threadspawn ctx ~multiple lval f args fctx = ctx.local let event ctx e octx = diff --git a/src/analyses/base.ml b/src/analyses/base.ml index e824fac013..01646a54cf 100644 --- a/src/analyses/base.ml +++ b/src/analyses/base.ml @@ -2513,7 +2513,7 @@ struct let st = special_unknown_invalidate ctx (Analyses.ask_of_ctx ctx) ctx.global st f args in [st] - let threadspawn ctx (lval: lval option) (f: varinfo) (args: exp list) fctx: D.t = + let threadspawn ctx ~multiple (lval: lval option) (f: varinfo) (args: exp list) fctx: D.t = begin match lval with | Some lval -> begin match ThreadId.get_current (Analyses.ask_of_ctx fctx) with diff --git a/src/analyses/condVars.ml b/src/analyses/condVars.ml index 820ff69efa..3b23dc03fc 100644 --- a/src/analyses/condVars.ml +++ b/src/analyses/condVars.ml @@ -156,7 +156,7 @@ struct let startstate v = D.bot () let threadenter ctx ~multiple lval f args = [D.bot ()] - let threadspawn ctx lval f args fctx = ctx.local + let threadspawn ctx ~multiple lval f args fctx = ctx.local let exitstate v = D.bot () end diff --git a/src/analyses/expsplit.ml b/src/analyses/expsplit.ml index 141a04283b..fef3d9ff9f 100644 --- a/src/analyses/expsplit.ml +++ b/src/analyses/expsplit.ml @@ -86,7 +86,7 @@ struct let threadenter ctx ~multiple lval f args = [ctx.local] - let threadspawn ctx lval f args fctx = + let threadspawn ctx ~multiple lval f args fctx = emit_splits_ctx ctx let event ctx (event: Events.t) octx = diff --git a/src/analyses/extractPthread.ml b/src/analyses/extractPthread.ml index f72f72c1fe..f084a21edb 100644 --- a/src/analyses/extractPthread.ml +++ b/src/analyses/extractPthread.ml @@ -1254,7 +1254,7 @@ module Spec : Analyses.MCPSpec = struct [ { f_d with pred = d.pred } ] - let threadspawn ctx lval f args fctx = ctx.local + let threadspawn ctx ~multiple lval f args fctx = ctx.local let exitstate v = D.top () diff --git a/src/analyses/fileUse.ml b/src/analyses/fileUse.ml index b8e7fd78f5..58257b7843 100644 --- a/src/analyses/fileUse.ml +++ b/src/analyses/fileUse.ml @@ -288,7 +288,7 @@ struct let startstate v = D.bot () let threadenter ctx ~multiple lval f args = [D.bot ()] - let threadspawn ctx lval f args fctx = ctx.local + let threadspawn ctx ~multiple lval f args fctx = ctx.local let exitstate v = D.bot () end diff --git a/src/analyses/mCP.ml b/src/analyses/mCP.ml index 5259bdb6c7..7a7e787ad7 100644 --- a/src/analyses/mCP.ml +++ b/src/analyses/mCP.ml @@ -578,7 +578,7 @@ struct (* TODO: this do_emits is now different from everything else *) map (fun d -> do_emits ctx !emits d false) @@ map topo_sort_an @@ n_cartesian_product css - let threadspawn (ctx:(D.t, G.t, C.t, V.t) ctx) lval f a fctx = + let threadspawn (ctx:(D.t, G.t, C.t, V.t) ctx) ~multiple lval f a fctx = let sides = ref [] in let emits = ref [] in let ctx'' = outer_ctx "threadspawn" ~sides ~emits ctx in @@ -586,7 +586,7 @@ struct let f post_all (n,(module S:MCPSpec),(d,fd)) = let ctx' : (S.D.t, S.G.t, S.C.t, S.V.t) ctx = inner_ctx "threadspawn" ~post_all ctx'' n d in let fctx' : (S.D.t, S.G.t, S.C.t, S.V.t) ctx = inner_ctx "threadspawn" ~post_all fctx'' n fd in - n, repr @@ S.threadspawn ctx' lval f a fctx' + n, repr @@ S.threadspawn ~multiple ctx' lval f a fctx' in let d, q = map_deadcode f @@ spec_list2 ctx.local fctx.local in do_sideg ctx !sides; diff --git a/src/analyses/mallocFresh.ml b/src/analyses/mallocFresh.ml index e171ad4ea1..b45573a801 100644 --- a/src/analyses/mallocFresh.ml +++ b/src/analyses/mallocFresh.ml @@ -55,7 +55,7 @@ struct let threadenter ctx ~multiple lval f args = [D.empty ()] - let threadspawn ctx lval f args fctx = + let threadspawn ctx ~multiple lval f args fctx = D.empty () module A = diff --git a/src/analyses/malloc_null.ml b/src/analyses/malloc_null.ml index 41c251dfce..f993db0c6e 100644 --- a/src/analyses/malloc_null.ml +++ b/src/analyses/malloc_null.ml @@ -216,7 +216,7 @@ struct let startstate v = D.empty () let threadenter ctx ~multiple lval f args = [D.empty ()] - let threadspawn ctx lval f args fctx = ctx.local + let threadspawn ctx ~multiple lval f args fctx = ctx.local let exitstate v = D.empty () let init marshal = diff --git a/src/analyses/mutexTypeAnalysis.ml b/src/analyses/mutexTypeAnalysis.ml index 66e60aede1..e640a261cd 100644 --- a/src/analyses/mutexTypeAnalysis.ml +++ b/src/analyses/mutexTypeAnalysis.ml @@ -66,7 +66,7 @@ struct let startstate v = D.bot () let threadenter ctx ~multiple lval f args = [D.top ()] - let threadspawn ctx lval f args fctx = ctx.local + let threadspawn ctx ~multiple lval f args fctx = ctx.local let exitstate v = D.top () let query ctx (type a) (q: a Queries.t): a Queries.result = diff --git a/src/analyses/region.ml b/src/analyses/region.ml index 86cad5684b..652526543c 100644 --- a/src/analyses/region.ml +++ b/src/analyses/region.ml @@ -177,7 +177,7 @@ struct let threadenter ctx ~multiple lval f args = [`Lifted (RegMap.bot ())] - let threadspawn ctx lval f args fctx = ctx.local + let threadspawn ctx ~multiple lval f args fctx = ctx.local let exitstate v = `Lifted (RegMap.bot ()) diff --git a/src/analyses/spec.ml b/src/analyses/spec.ml index c44edd6c87..2f754f6160 100644 --- a/src/analyses/spec.ml +++ b/src/analyses/spec.ml @@ -488,7 +488,7 @@ struct let startstate v = D.bot () let threadenter ctx ~multiple lval f args = [D.bot ()] - let threadspawn ctx lval f args fctx = ctx.local + let threadspawn ctx ~multiple lval f args fctx = ctx.local let exitstate v = D.bot () end diff --git a/src/analyses/symbLocks.ml b/src/analyses/symbLocks.ml index 32be32f73d..f6fdd96c2e 100644 --- a/src/analyses/symbLocks.ml +++ b/src/analyses/symbLocks.ml @@ -30,7 +30,7 @@ struct let startstate v = D.top () let threadenter ctx ~multiple lval f args = [D.top ()] - let threadspawn ctx lval f args fctx = ctx.local + let threadspawn ctx ~multiple lval f args fctx = ctx.local let exitstate v = D.top () let branch ctx exp tv = ctx.local diff --git a/src/analyses/taintPartialContexts.ml b/src/analyses/taintPartialContexts.ml index b45ea54877..88cf532ab2 100644 --- a/src/analyses/taintPartialContexts.ml +++ b/src/analyses/taintPartialContexts.ml @@ -103,7 +103,7 @@ struct let startstate v = D.bot () let threadenter ctx ~multiple lval f args = [D.bot ()] - let threadspawn ctx lval f args fctx = + let threadspawn ctx ~multiple lval f args fctx = match lval with | Some lv -> taint_lval ctx lv | None -> ctx.local diff --git a/src/analyses/threadAnalysis.ml b/src/analyses/threadAnalysis.ml index ff4b4d5c63..f51e9395db 100644 --- a/src/analyses/threadAnalysis.ml +++ b/src/analyses/threadAnalysis.ml @@ -91,7 +91,7 @@ struct ctx.sideg tid (true, TS.bot (), false)); [D.bot ()] - let threadspawn ctx lval f args fctx = + let threadspawn ctx ~multiple lval f args fctx = let creator = ThreadId.get_current (Analyses.ask_of_ctx ctx) in let tid = ThreadId.get_current_unlift (Analyses.ask_of_ctx fctx) in let repeated = D.mem tid ctx.local in diff --git a/src/analyses/threadEscape.ml b/src/analyses/threadEscape.ml index 0948a3976d..21a8b69c93 100644 --- a/src/analyses/threadEscape.ml +++ b/src/analyses/threadEscape.ml @@ -153,7 +153,7 @@ struct let threadenter ctx ~multiple lval f args = [D.bot ()] - let threadspawn ctx lval f args fctx = + let threadspawn ctx ~multiple lval f args fctx = D.join ctx.local @@ match args with | [ptc_arg] -> diff --git a/src/analyses/threadFlag.ml b/src/analyses/threadFlag.ml index 81e05af679..6bd466caef 100644 --- a/src/analyses/threadFlag.ml +++ b/src/analyses/threadFlag.ml @@ -63,7 +63,7 @@ struct ctx.emit Events.EnterMultiThreaded; [create_tid f] - let threadspawn ctx lval f args fctx = + let threadspawn ctx ~multiple lval f args fctx = if not (has_ever_been_multi (Analyses.ask_of_ctx ctx)) then ctx.emit Events.EnterMultiThreaded; D.join ctx.local (Flag.get_main ()) diff --git a/src/analyses/threadId.ml b/src/analyses/threadId.ml index a9f3fa35f7..900870a676 100644 --- a/src/analyses/threadId.ml +++ b/src/analyses/threadId.ml @@ -58,8 +58,8 @@ struct let create_tid ?(multiple=false) (_, current, (td, _)) ((node, index): Node.t * int option) v = match current with - | `Lifted current when not multiple -> - let+ tid = Thread.threadenter (current, td) node index v in + | `Lifted current -> + let+ tid = Thread.threadenter ~multiple (current, td) node index v in if GobConfig.get_bool "dbg.print_tids" then Hashtbl.replace !tids tid (); `Lifted tid @@ -138,10 +138,10 @@ struct let+ tid = create_tid ~multiple ctx.local (n, i) f in (`Lifted (f, n, i), tid, (TD.bot (), TD.bot ())) - let threadspawn ctx lval f args fctx = + let threadspawn ctx ~multiple lval f args fctx = let (current_n, current, (td,tdl)) = ctx.local in let v, n, i = match fctx.local with `Lifted vni, _, _ -> vni | _ -> failwith "ThreadId.threadspawn" in - (current_n, current, (Thread.threadspawn td n i v, Thread.threadspawn tdl n i v)) + (current_n, current, (Thread.threadspawn ~multiple td n i v, Thread.threadspawn ~multiple tdl n i v)) type marshal = (Thread.t,unit) Hashtbl.t (* TODO: don't use polymorphic Hashtbl *) let init (m:marshal option): unit = diff --git a/src/analyses/threadJoins.ml b/src/analyses/threadJoins.ml index f2cd36619f..862711073c 100644 --- a/src/analyses/threadJoins.ml +++ b/src/analyses/threadJoins.ml @@ -81,7 +81,7 @@ struct ) | _, _ -> ctx.local - let threadspawn ctx lval f args fctx = + let threadspawn ctx ~multiple lval f args fctx = if D.is_bot ctx.local then ( (* bot is All threads *) M.info ~category:Imprecise "Thread created while ALL threads must-joined, continuing with no threads joined."; D.top () (* top is no threads *) diff --git a/src/analyses/tmpSpecial.ml b/src/analyses/tmpSpecial.ml index 046345e627..9ed6da7c60 100644 --- a/src/analyses/tmpSpecial.ml +++ b/src/analyses/tmpSpecial.ml @@ -89,7 +89,7 @@ struct let startstate v = D.bot () let threadenter ctx ~multiple lval f args = [D.bot ()] - let threadspawn ctx lval f args fctx = ctx.local + let threadspawn ctx ~multiple lval f args fctx = ctx.local let exitstate v = D.bot () end diff --git a/src/analyses/tutorials/taint.ml b/src/analyses/tutorials/taint.ml index 7fc3fd7343..a978d0faf4 100644 --- a/src/analyses/tutorials/taint.ml +++ b/src/analyses/tutorials/taint.ml @@ -130,7 +130,7 @@ struct (* You may leave these alone *) let startstate v = D.bot () let threadenter ctx ~multiple lval f args = [D.top ()] - let threadspawn ctx lval f args fctx = ctx.local + let threadspawn ctx ~multiple lval f args fctx = ctx.local let exitstate v = D.top () end diff --git a/src/analyses/tutorials/unitAnalysis.ml b/src/analyses/tutorials/unitAnalysis.ml index 3ecddc2bc0..dc377cdd97 100644 --- a/src/analyses/tutorials/unitAnalysis.ml +++ b/src/analyses/tutorials/unitAnalysis.ml @@ -40,7 +40,7 @@ struct let startstate v = D.bot () let threadenter ctx ~multiple lval f args = [D.top ()] - let threadspawn ctx lval f args fctx = ctx.local + let threadspawn ctx ~multiple lval f args fctx = ctx.local let exitstate v = D.top () end diff --git a/src/analyses/uninit.ml b/src/analyses/uninit.ml index 2b388d1190..8693599a4d 100644 --- a/src/analyses/uninit.ml +++ b/src/analyses/uninit.ml @@ -26,7 +26,7 @@ struct let startstate v : D.t = D.empty () let threadenter ctx ~multiple lval f args = [D.empty ()] - let threadspawn ctx lval f args fctx = ctx.local + let threadspawn ctx ~multiple lval f args fctx = ctx.local let exitstate v : D.t = D.empty () let access_address (ask: Queries.ask) write lv = diff --git a/src/analyses/useAfterFree.ml b/src/analyses/useAfterFree.ml index 0c7a46c35f..683ddbdcc2 100644 --- a/src/analyses/useAfterFree.ml +++ b/src/analyses/useAfterFree.ml @@ -197,7 +197,7 @@ struct | _ -> state let threadenter ctx ~multiple lval f args = [ctx.local] - let threadspawn ctx lval f args fctx = ctx.local + let threadspawn ctx ~multiple lval f args fctx = ctx.local let startstate v = D.bot () let exitstate v = D.top () diff --git a/src/analyses/varEq.ml b/src/analyses/varEq.ml index 3aaef95265..3f5a65516f 100644 --- a/src/analyses/varEq.ml +++ b/src/analyses/varEq.ml @@ -44,7 +44,7 @@ struct let startstate v = D.top () let threadenter ctx ~multiple lval f args = [D.top ()] - let threadspawn ctx lval f args fctx = ctx.local + let threadspawn ctx ~multiple lval f args fctx = ctx.local let exitstate v = D.top () let typ_equal = CilType.Typ.equal (* TODO: Used to have equality checking, which ignores attributes. Is that needed? *) diff --git a/src/cdomains/threadIdDomain.ml b/src/cdomains/threadIdDomain.ml index 7193552048..a9646cffd2 100644 --- a/src/cdomains/threadIdDomain.ml +++ b/src/cdomains/threadIdDomain.ml @@ -23,7 +23,7 @@ module type Stateless = sig include S - val threadenter: Node.t -> int option -> varinfo -> t + val threadenter: multiple:bool -> Node.t -> int option -> varinfo -> t end module type Stateful = @@ -32,8 +32,8 @@ sig module D: Lattice.S - val threadenter: t * D.t -> Node.t -> int option -> varinfo -> t list - val threadspawn: D.t -> Node.t -> int option -> varinfo -> D.t + val threadenter: multiple:bool -> t * D.t -> Node.t -> int option -> varinfo -> t list + val threadspawn: multiple:bool -> D.t -> Node.t -> int option -> varinfo -> D.t (** If it is possible to get a list of threads created thus far, get it *) val created: t -> D.t -> (t list) option @@ -71,9 +71,10 @@ struct let threadinit v ~multiple: t = (v, None) - let threadenter l i v: t = + let threadenter ~multiple l i v: t = if GobConfig.get_bool "ana.thread.include-node" then - (v, Some (l, i)) + let counter = Option.map (fun x -> if multiple then WrapperFunctionAnalysis0.ThreadCreateUniqueCount.top () else x) i in + (v, Some (l, counter)) else (v, None) @@ -93,8 +94,8 @@ struct module D = Lattice.Unit - let threadenter _ n i v = [threadenter n i v] - let threadspawn () _ _ _ = () + let threadenter ~multiple _ n i v = [threadenter ~multiple n i v] + let threadspawn ~multiple () _ _ _ = () let created _ _ = None end @@ -162,10 +163,10 @@ struct else ([base_tid], S.empty ()) - let threadenter ((p, _ ) as current, (cs,_)) (n: Node.t) i v = - let ni = Base.threadenter n i v in + let threadenter ~multiple ((p, _ ) as current, (cs,_)) (n: Node.t) i v = + let ni = Base.threadenter ~multiple n i v in let ((p', s') as composed) = compose current ni in - if is_unique composed && S.mem ni cs then + if is_unique composed && (S.mem ni cs || multiple) then [(p, S.singleton ni); composed] (* also respawn unique version of the thread to keep it reachable while thread ID sets refer to it *) else [composed] @@ -182,12 +183,12 @@ struct in Some (List.concat_map map_one els) - let threadspawn (cs,cms) l i v = - let e = Base.threadenter l i v in + let threadspawn ~multiple (cs,cms) l i v = + let e = Base.threadenter ~multiple l i v in if S.mem e cs then (cs, S.add e cms) else - (S.add e cs, cms) + (S.add e cs, if multiple then S.add e cms else cms) let is_main = function | ([fl], s) when S.is_empty s && Base.is_main fl -> true @@ -257,24 +258,24 @@ struct | (None, Some x'), `Top -> liftp x' (P.D.top ()) | _ -> None - let threadenter x n i v = + let threadenter ~multiple x n i v = match x with - | ((Some x', None), `Lifted1 d) -> H.threadenter (x',d) n i v |> List.map (fun t -> (Some t, None)) - | ((Some x', None), `Bot) -> H.threadenter (x',H.D.bot ()) n i v |> List.map (fun t -> (Some t, None)) - | ((Some x', None), `Top) -> H.threadenter (x',H.D.top ()) n i v |> List.map (fun t -> (Some t, None)) - | ((None, Some x'), `Lifted2 d) -> P.threadenter (x',d) n i v |> List.map (fun t -> (None, Some t)) - | ((None, Some x'), `Bot) -> P.threadenter (x',P.D.bot ()) n i v |> List.map (fun t -> (None, Some t)) - | ((None, Some x'), `Top) -> P.threadenter (x',P.D.top ()) n i v |> List.map (fun t -> (None, Some t)) + | ((Some x', None), `Lifted1 d) -> H.threadenter ~multiple (x',d) n i v |> List.map (fun t -> (Some t, None)) + | ((Some x', None), `Bot) -> H.threadenter ~multiple (x',H.D.bot ()) n i v |> List.map (fun t -> (Some t, None)) + | ((Some x', None), `Top) -> H.threadenter ~multiple (x',H.D.top ()) n i v |> List.map (fun t -> (Some t, None)) + | ((None, Some x'), `Lifted2 d) -> P.threadenter ~multiple (x',d) n i v |> List.map (fun t -> (None, Some t)) + | ((None, Some x'), `Bot) -> P.threadenter ~multiple (x',P.D.bot ()) n i v |> List.map (fun t -> (None, Some t)) + | ((None, Some x'), `Top) -> P.threadenter ~multiple (x',P.D.top ()) n i v |> List.map (fun t -> (None, Some t)) | _ -> failwith "FlagConfiguredTID received a value where not exactly one component is set" - let threadspawn x n i v = + let threadspawn ~multiple x n i v = match x with - | `Lifted1 x' -> `Lifted1 (H.threadspawn x' n i v) - | `Lifted2 x' -> `Lifted2 (P.threadspawn x' n i v) - | `Bot when history_enabled () -> `Lifted1 (H.threadspawn (H.D.bot ()) n i v) - | `Bot -> `Lifted2 (P.threadspawn (P.D.bot ()) n i v) - | `Top when history_enabled () -> `Lifted1 (H.threadspawn (H.D.top ()) n i v) - | `Top -> `Lifted2 (P.threadspawn (P.D.top ()) n i v) + | `Lifted1 x' -> `Lifted1 (H.threadspawn ~multiple x' n i v) + | `Lifted2 x' -> `Lifted2 (P.threadspawn ~multiple x' n i v) + | `Bot when history_enabled () -> `Lifted1 (H.threadspawn ~multiple (H.D.bot ()) n i v) + | `Bot -> `Lifted2 (P.threadspawn ~multiple (P.D.bot ()) n i v) + | `Top when history_enabled () -> `Lifted1 (H.threadspawn ~multiple (H.D.top ()) n i v) + | `Top -> `Lifted2 (P.threadspawn ~multiple (P.D.top ()) n i v) let name () = "FlagConfiguredTID: " ^ if history_enabled () then H.name () else P.name () end diff --git a/src/framework/analyses.ml b/src/framework/analyses.ml index 3bb88a6ead..e1a4560003 100644 --- a/src/framework/analyses.ml +++ b/src/framework/analyses.ml @@ -447,7 +447,7 @@ sig val threadenter : (D.t, G.t, C.t, V.t) ctx -> multiple:bool -> lval option -> varinfo -> exp list -> D.t list (** Updates the local state of the creator thread using initial state of created thread. *) - val threadspawn : (D.t, G.t, C.t, V.t) ctx -> lval option -> varinfo -> exp list -> (D.t, G.t, C.t, V.t) ctx -> D.t + val threadspawn : (D.t, G.t, C.t, V.t) ctx -> multiple:bool -> lval option -> varinfo -> exp list -> (D.t, G.t, C.t, V.t) ctx -> D.t val event : (D.t, G.t, C.t, V.t) ctx -> Events.t -> (D.t, G.t, C.t, V.t) ctx -> D.t end @@ -697,7 +697,7 @@ struct ctx.local let threadenter ctx ~multiple lval f args = [ctx.local] - let threadspawn ctx lval f args fctx = ctx.local + let threadspawn ctx ~multiple lval f args fctx = ctx.local end diff --git a/src/framework/constraints.ml b/src/framework/constraints.ml index ed492f4237..f474df6834 100644 --- a/src/framework/constraints.ml +++ b/src/framework/constraints.ml @@ -86,8 +86,8 @@ struct let threadenter ctx ~multiple lval f args = List.map D.lift @@ S.threadenter (conv ctx) ~multiple lval f args - let threadspawn ctx lval f args fctx = - D.lift @@ S.threadspawn (conv ctx) lval f args (conv fctx) + let threadspawn ctx ~multiple lval f args fctx = + D.lift @@ S.threadspawn (conv ctx) ~multiple lval f args (conv fctx) let paths_as_set ctx = List.map (fun x -> D.lift x) @@ S.paths_as_set (conv ctx) @@ -170,8 +170,8 @@ struct let threadenter ctx ~multiple lval f args = S.threadenter (conv ctx) ~multiple lval f args - let threadspawn ctx lval f args fctx = - S.threadspawn (conv ctx) lval f args (conv fctx) + let threadspawn ctx ~multiple lval f args fctx = + S.threadspawn (conv ctx) ~multiple lval f args (conv fctx) let paths_as_set ctx = S.paths_as_set (conv ctx) let event ctx e octx = S.event (conv ctx) e (conv octx) @@ -250,7 +250,7 @@ struct let combine_assign' ctx r fe f args fc es f_ask = lift_fun ctx (lift ctx) S.combine_assign (fun p -> p r fe f args fc (fst es) f_ask) let threadenter ctx ~multiple lval f args = lift_fun ctx (List.map lift_start_level) (S.threadenter ~multiple) ((|>) args % (|>) f % (|>) lval) - let threadspawn ctx lval f args fctx = lift_fun ctx (lift ctx) S.threadspawn ((|>) (conv fctx) % (|>) args % (|>) f % (|>) lval) + let threadspawn ctx ~multiple lval f args fctx = lift_fun ctx (lift ctx) (S.threadspawn ~multiple) ((|>) (conv fctx) % (|>) args % (|>) f % (|>) lval) let leq0 = function | `Top -> false @@ -395,7 +395,7 @@ struct let event ctx e octx = lift_fun ctx S.event ((|>) (conv octx) % (|>) e) let threadenter ctx ~multiple lval f args = S.threadenter (conv ctx) ~multiple lval f args |> List.map (fun d -> (d, snd ctx.local)) - let threadspawn ctx lval f args fctx = lift_fun ctx S.threadspawn ((|>) (conv fctx) % (|>) args % (|>) f % (|>) lval) + let threadspawn ctx ~multiple lval f args fctx = lift_fun ctx (S.threadspawn ~multiple) ((|>) (conv fctx) % (|>) args % (|>) f % (|>) lval) let enter ctx r f args = let m = snd ctx.local in @@ -486,7 +486,7 @@ struct let combine_assign ctx r fe f args fc es f_ask = lift_fun ctx D.lift S.combine_assign (fun p -> p r fe f args fc (D.unlift es) f_ask) `Bot let threadenter ctx ~multiple lval f args = lift_fun ctx (List.map D.lift) (S.threadenter ~multiple) ((|>) args % (|>) f % (|>) lval) [] - let threadspawn ctx lval f args fctx = lift_fun ctx D.lift S.threadspawn ((|>) (conv fctx) % (|>) args % (|>) f % (|>) lval) `Bot + let threadspawn ctx ~multiple lval f args fctx = lift_fun ctx D.lift (S.threadspawn ~multiple) ((|>) (conv fctx) % (|>) args % (|>) f % (|>) lval) `Bot let event (ctx:(D.t,G.t,C.t,V.t) ctx) (e:Events.t) (octx:(D.t,G.t,C.t,V.t) ctx):D.t = lift_fun ctx D.lift S.event ((|>) (conv octx) % (|>) e) `Bot end @@ -563,7 +563,7 @@ struct if !AnalysisState.postsolving then sideg (GVar.contexts f) (G.create_contexts (G.CSet.singleton c)) - let common_ctx var edge prev_node pval (getl:lv -> ld) sidel getg sideg : (D.t, S.G.t, S.C.t, S.V.t) ctx * D.t list ref * (lval option * varinfo * exp list * D.t) list ref = + let common_ctx var edge prev_node pval (getl:lv -> ld) sidel getg sideg : (D.t, S.G.t, S.C.t, S.V.t) ctx * D.t list ref * (lval option * varinfo * exp list * D.t * bool) list ref = let r = ref [] in let spawns = ref [] in (* now watch this ... *) @@ -586,7 +586,7 @@ struct (* TODO: don't repeat for all paths that spawn same *) let ds = S.threadenter ~multiple ctx lval f args in List.iter (fun d -> - spawns := (lval, f, args, d) :: !spawns; + spawns := (lval, f, args, d, multiple) :: !spawns; match Cilfacade.find_varinfo_fundec f with | fd -> let c = S.context fd d in @@ -618,14 +618,14 @@ struct } in (* TODO: don't forget path dependencies *) - let one_spawn (lval, f, args, fd) = + let one_spawn (lval, f, args, fd, multiple) = let rec fctx = { ctx with ask = (fun (type a) (q: a Queries.t) -> S.query fctx q) ; local = fd } in - S.threadspawn ctx' lval f args fctx + S.threadspawn ctx' ~multiple lval f args fctx in bigsqcup (List.map one_spawn spawns) @@ -1266,9 +1266,9 @@ struct let g xs ys = (List.map (fun y -> D.singleton y) ys) @ xs in fold' ctx (Spec.threadenter ~multiple) (fun h -> h lval f args) g [] - let threadspawn ctx lval f args fctx = + let threadspawn ctx ~multiple lval f args fctx = let fd1 = D.choose fctx.local in - map ctx Spec.threadspawn (fun h -> h lval f args (conv fctx fd1)) + map ctx (Spec.threadspawn ~multiple) (fun h -> h lval f args (conv fctx fd1)) let sync ctx reason = map ctx Spec.sync (fun h -> h reason) @@ -1450,7 +1450,7 @@ struct let combine_assign ctx = S.combine_assign (conv ctx) let special ctx = S.special (conv ctx) let threadenter ctx = S.threadenter (conv ctx) - let threadspawn ctx lv f args fctx = S.threadspawn (conv ctx) lv f args (conv fctx) + let threadspawn ctx ~multiple lv f args fctx = S.threadspawn (conv ctx) ~multiple lv f args (conv fctx) let sync ctx = S.sync (conv ctx) let skip ctx = S.skip (conv ctx) let asm ctx = S.asm (conv ctx) @@ -1686,7 +1686,7 @@ struct S.D.bot () | _ -> S.special conv_ctx lv f args let threadenter ctx = S.threadenter (conv ctx) - let threadspawn ctx lv f args fctx = S.threadspawn (conv ctx) lv f args (conv fctx) + let threadspawn ctx ~multiple lv f args fctx = S.threadspawn (conv ctx) ~multiple lv f args (conv fctx) let sync ctx = S.sync (conv ctx) let skip ctx = S.skip (conv ctx) let asm ctx = S.asm (conv ctx) diff --git a/src/util/wideningTokens.ml b/src/util/wideningTokens.ml index 73c160e3bb..1816de90c7 100644 --- a/src/util/wideningTokens.ml +++ b/src/util/wideningTokens.ml @@ -180,6 +180,6 @@ struct let combine_assign ctx r fe f args fc es f_ask = lift_fun ctx lift' S.combine_assign (fun p -> p r fe f args fc (D.unlift es) f_ask) (* TODO: use tokens from es *) let threadenter ctx ~multiple lval f args = lift_fun ctx (fun l ts -> List.map (Fun.flip lift' ts) l) (S.threadenter ~multiple) ((|>) args % (|>) f % (|>) lval ) - let threadspawn ctx lval f args fctx = lift_fun ctx lift' S.threadspawn ((|>) (conv fctx) % (|>) args % (|>) f % (|>) lval) + let threadspawn ctx ~multiple lval f args fctx = lift_fun ctx lift' (S.threadspawn ~multiple) ((|>) (conv fctx) % (|>) args % (|>) f % (|>) lval) let event ctx e octx = lift_fun ctx lift' S.event ((|>) (conv octx) % (|>) e) end diff --git a/src/witness/observerAnalysis.ml b/src/witness/observerAnalysis.ml index 45a547c471..e8daf56155 100644 --- a/src/witness/observerAnalysis.ml +++ b/src/witness/observerAnalysis.ml @@ -77,7 +77,7 @@ struct let startstate v = `Lifted Automaton.initial let threadenter ctx ~multiple lval f args = [D.top ()] - let threadspawn ctx lval f args fctx = ctx.local + let threadspawn ctx ~multiple lval f args fctx = ctx.local let exitstate v = D.top () end diff --git a/src/witness/witnessConstraints.ml b/src/witness/witnessConstraints.ml index 1bf6294020..8dedf77a79 100644 --- a/src/witness/witnessConstraints.ml +++ b/src/witness/witnessConstraints.ml @@ -209,9 +209,9 @@ struct ys' @ xs in fold' ctx (Spec.threadenter ~multiple) (fun h -> h lval f args) g [] - let threadspawn ctx lval f args fctx = + let threadspawn ctx ~multiple lval f args fctx = let fd1 = Dom.choose_key (fst fctx.local) in - map ctx Spec.threadspawn (fun h -> h lval f args (conv fctx fd1)) + map ctx (Spec.threadspawn ~multiple) (fun h -> h lval f args (conv fctx fd1)) let sync ctx reason = fold'' ctx Spec.sync (fun h -> h reason) (fun (a, async) x r a' -> From 44ef0843efac4839f45f267f015ace6a27a88414 Mon Sep 17 00:00:00 2001 From: Michael Schwarz Date: Thu, 28 Sep 2023 13:54:36 +0200 Subject: [PATCH 023/140] Add example for race despite uniqueness counter --- .../40-threadid/11-multiple-unique-counter.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 tests/regression/40-threadid/11-multiple-unique-counter.c diff --git a/tests/regression/40-threadid/11-multiple-unique-counter.c b/tests/regression/40-threadid/11-multiple-unique-counter.c new file mode 100644 index 0000000000..37c08ae61a --- /dev/null +++ b/tests/regression/40-threadid/11-multiple-unique-counter.c @@ -0,0 +1,16 @@ +// PARAM: --set ana.thread.unique_thread_id_count 4 +#include +#include + +int myglobal; + +void *t_fun(void *arg) { + myglobal=40; //RACE + return NULL; +} + +int main(void) { + // This should spawn a non-unique thread + unknown(t_fun); + return 0; +} From b718e46241c0c4f9b926620060a8743c3c49b6d7 Mon Sep 17 00:00:00 2001 From: Michael Schwarz Date: Thu, 28 Sep 2023 14:04:49 +0200 Subject: [PATCH 024/140] Add check that only one mainfun is specified to privatizations --- src/analyses/basePriv.ml | 2 +- src/analyses/commonPriv.ml | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/analyses/basePriv.ml b/src/analyses/basePriv.ml index 0154924a1c..3843dda300 100644 --- a/src/analyses/basePriv.ml +++ b/src/analyses/basePriv.ml @@ -893,7 +893,7 @@ end module MinePrivBase = struct include NoFinalize - include ConfCheck.RequireMutexPathSensInit + include ConfCheck.RequireMutexPathSensOneMainInit include MutexGlobals (* explicit not needed here because G is Prod anyway? *) let thread_join ?(force=false) ask get e st = st diff --git a/src/analyses/commonPriv.ml b/src/analyses/commonPriv.ml index 1b92cb320d..38a8dfe1b7 100644 --- a/src/analyses/commonPriv.ml +++ b/src/analyses/commonPriv.ml @@ -19,12 +19,14 @@ struct if not mutex_active then failwith "Privatization (to be useful) requires the 'mutex' analysis to be enabled (it is currently disabled)" end - module RequireMutexPathSensInit = + module RequireMutexPathSensOneMainInit = struct let init () = RequireMutexActivatedInit.init (); let mutex_path_sens = List.mem "mutex" (GobConfig.get_string_list "ana.path_sens") in if not mutex_path_sens then failwith "The activated privatization requires the 'mutex' analysis to be enabled & path sensitive (it is currently enabled, but not path sensitive)"; + let mainfuns = List.length @@ GobConfig.get_list "mainfun" in + if not (mainfuns = 1) then failwith "The activated privatization requires exactly one main function to be specified"; () end From dee2a60ba7855321f2d67513ca97be8cdbe3320d Mon Sep 17 00:00:00 2001 From: Stanimir Bozhilov Date: Mon, 2 Oct 2023 01:02:38 +0200 Subject: [PATCH 025/140] Set SV-COMP memory safety global flags at all necessary locations --- src/analyses/base.ml | 10 +++++--- src/analyses/memLeak.ml | 4 ++-- src/analyses/memOutOfBounds.ml | 42 +++++++++++++++++----------------- src/analyses/useAfterFree.ml | 6 +++-- 4 files changed, 34 insertions(+), 28 deletions(-) diff --git a/src/analyses/base.ml b/src/analyses/base.ml index d9cfba7b18..a624fd0b40 100644 --- a/src/analyses/base.ml +++ b/src/analyses/base.ml @@ -2027,12 +2027,16 @@ struct in match eval_rv_address (Analyses.ask_of_ctx ctx) ctx.global ctx.local ptr with | Address a -> - if AD.is_top a then + if AD.is_top a then ( + AnalysisStateUtil.set_mem_safety_flag InvalidFree; M.warn ~category:(Behavior (Undefined InvalidMemoryDeallocation)) ~tags:[CWE 590] "Points-to set for pointer %a in function %s is top. Potentially invalid memory deallocation may occur" d_exp ptr special_fn.vname - else if has_non_heap_var a then + ) else if has_non_heap_var a then ( + AnalysisStateUtil.set_mem_safety_flag InvalidFree; M.warn ~category:(Behavior (Undefined InvalidMemoryDeallocation)) ~tags:[CWE 590] "Free of non-dynamically allocated memory in function %s for pointer %a" special_fn.vname d_exp ptr - else if has_non_zero_offset a then + ) else if has_non_zero_offset a then ( + AnalysisStateUtil.set_mem_safety_flag InvalidFree; M.warn ~category:(Behavior (Undefined InvalidMemoryDeallocation)) ~tags:[CWE 761] "Free of memory not at start of buffer in function %s for pointer %a" special_fn.vname d_exp ptr + ) | _ -> M.warn ~category:MessageCategory.Analyzer "Pointer %a in function %s doesn't evaluate to a valid address." d_exp ptr special_fn.vname diff --git a/src/analyses/memLeak.ml b/src/analyses/memLeak.ml index 56cbbbff3d..eb38b97a1c 100644 --- a/src/analyses/memLeak.ml +++ b/src/analyses/memLeak.ml @@ -30,10 +30,10 @@ struct if not @@ D.is_empty state then match assert_exp_imprecise, exp with | true, Some exp -> - AnalysisStateUtil.set_mem_safety_flag InvalidMemTrack; + set_mem_safety_flag InvalidMemTrack; M.warn ~category:(Behavior (Undefined MemoryLeak)) ~tags:[CWE 401] "assert expression %a is unknown. Memory leak might possibly occur for heap variables: %a" d_exp exp D.pretty state | _ -> - AnalysisStateUtil.set_mem_safety_flag InvalidMemTrack; + set_mem_safety_flag InvalidMemTrack; M.warn ~category:(Behavior (Undefined MemoryLeak)) ~tags:[CWE 401] "Memory leak detected for heap variables: %a" D.pretty state (* TRANSFER FUNCTIONS *) diff --git a/src/analyses/memOutOfBounds.ml b/src/analyses/memOutOfBounds.ml index 9ee022fe08..db86a63414 100644 --- a/src/analyses/memOutOfBounds.ml +++ b/src/analyses/memOutOfBounds.ml @@ -118,6 +118,7 @@ struct | x::xs -> List.fold_left VDQ.ID.join x xs end | _ -> + set_mem_safety_flag InvalidDeref; M.warn "Pointer %a has a points-to-set of top. An invalid memory access might occur" d_exp ptr; `Top @@ -172,7 +173,7 @@ struct | _ -> true in if may_contain_unknown_addr then begin - (* set_mem_safety_flag InvalidDeref; *) + set_mem_safety_flag InvalidDeref; M.warn ~category:(Behavior (Undefined Other)) "Pointer %a contains an unknown address. Invalid dereference may occur" d_exp ptr end @@ -201,15 +202,13 @@ struct | Addr (_, o) -> ID.is_bot @@ offs_to_idx t o | _ -> false ) a then ( - (* TODO: Uncomment once staging-memsafety branch changes are applied *) - (* set_mem_safety_flag InvalidDeref; *) + set_mem_safety_flag InvalidDeref; M.warn "Pointer %a has a bot address offset. An invalid memory access may occur" d_exp ptr ) else if VDQ.AD.exists (function | Addr (_, o) -> ID.is_bot @@ offs_to_idx t o | _ -> false ) a then ( - (* TODO: Uncomment once staging-memsafety branch changes are applied *) - (* set_mem_safety_flag InvalidDeref; *) + set_mem_safety_flag InvalidDeref; M.warn "Pointer %a has a top address offset. An invalid memory access may occur" d_exp ptr ); (* Offset should be the same for all elements in the points-to set *) @@ -224,7 +223,7 @@ struct ID.top_of @@ Cilfacade.ptrdiff_ikind () end | _ -> - (* set_mem_safety_flag InvalidDeref; *) + set_mem_safety_flag InvalidDeref; M.warn "Pointer %a has a points-to-set of top. An invalid memory access might occur" d_exp ptr; ID.top_of @@ Cilfacade.ptrdiff_ikind () @@ -259,10 +258,10 @@ struct | Some t -> begin match ptr_size, addr_offs with | `Top, _ -> - AS.svcomp_may_invalid_deref := true; + set_mem_safety_flag InvalidDeref; M.warn ~category:(Behavior behavior) ~tags:[CWE cwe_number] "Size of pointer %a is top. Memory out-of-bounds access might occur due to pointer arithmetic" d_exp lval_exp | `Bot, _ -> - AS.svcomp_may_invalid_deref := true; + set_mem_safety_flag InvalidDeref; M.warn ~category:(Behavior behavior) ~tags:[CWE cwe_number] "Size of pointer %a is bot. Memory out-of-bounds access might occur due to pointer arithmetic" d_exp lval_exp | `Lifted ps, ao -> let casted_ps = ID.cast_to (Cilfacade.ptrdiff_ikind ()) ps in @@ -270,11 +269,11 @@ struct let ptr_size_lt_offs = ID.lt casted_ps casted_ao in begin match ID.to_bool ptr_size_lt_offs with | Some true -> - AnalysisState.svcomp_may_invalid_deref := true; + set_mem_safety_flag InvalidDeref; M.warn ~category:(Behavior behavior) ~tags:[CWE cwe_number] "Size of pointer is %a (in bytes). It is offset by %a (in bytes) due to pointer arithmetic. Memory out-of-bounds access must occur" ID.pretty casted_ps ID.pretty casted_ao | Some false -> () | None -> - AnalysisState.svcomp_may_invalid_deref := true; + set_mem_safety_flag InvalidDeref; M.warn ~category:(Behavior behavior) ~tags:[CWE cwe_number] "Could not compare size of pointer (%a) (in bytes) with offset by (%a) (in bytes). Memory out-of-bounds access might occur" ID.pretty casted_ps ID.pretty casted_ao end end @@ -334,16 +333,16 @@ struct in begin match ptr_size, offset_size_with_addr_size with | `Top, _ -> - AS.svcomp_may_invalid_deref := true; + set_mem_safety_flag InvalidDeref; M.warn ~category:(Behavior behavior) ~tags:[CWE cwe_number] "Size of pointer %a in expression %a is top. Memory out-of-bounds access might occur" d_exp e1 d_exp binopexp | _, `Top -> - AS.svcomp_may_invalid_deref := true; + set_mem_safety_flag InvalidDeref; M.warn ~category:(Behavior behavior) ~tags:[CWE cwe_number] "Operand value for pointer arithmetic in expression %a is top. Memory out-of-bounds access might occur" d_exp binopexp | `Bot, _ -> - AS.svcomp_may_invalid_deref := true; + set_mem_safety_flag InvalidDeref; M.warn ~category:(Behavior behavior) ~tags:[CWE cwe_number] "Size of pointer %a in expression %a is bottom. Memory out-of-bounds access might occur" d_exp e1 d_exp binopexp | _, `Bot -> - AS.svcomp_may_invalid_deref := true; + set_mem_safety_flag InvalidDeref; M.warn ~category:(Behavior behavior) ~tags:[CWE cwe_number] "Operand value for pointer arithmetic in expression %a is bottom. Memory out-of-bounds access might occur" d_exp binopexp | `Lifted ps, `Lifted o -> let casted_ps = ID.cast_to (Cilfacade.ptrdiff_ikind ()) ps in @@ -351,11 +350,11 @@ struct let ptr_size_lt_offs = ID.lt casted_ps casted_o in begin match ID.to_bool ptr_size_lt_offs with | Some true -> - AS.svcomp_may_invalid_deref := true; + set_mem_safety_flag InvalidDeref; M.warn ~category:(Behavior behavior) ~tags:[CWE cwe_number] "Size of pointer in expression %a is %a (in bytes). It is offset by %a (in bytes). Memory out-of-bounds access must occur" d_exp binopexp ID.pretty casted_ps ID.pretty casted_o | Some false -> () | None -> - AnalysisState.svcomp_may_invalid_deref := true; + set_mem_safety_flag InvalidDeref; M.warn ~category:(Behavior behavior) ~tags:[CWE cwe_number] "Could not compare pointer size (%a) with offset (%a). Memory out-of-bounds access may occur" ID.pretty casted_ps ID.pretty casted_o end end @@ -372,15 +371,16 @@ struct let addr_offs = get_addr_offs ctx dest in match dest_size, eval_n with | `Top, _ -> - AnalysisState.svcomp_may_invalid_deref := true; + set_mem_safety_flag InvalidDeref; M.warn ~category:(Behavior behavior) ~tags:[CWE cwe_number] "Size of dest %a in function %s is unknown. Memory out-of-bounds access might occur" d_exp dest fun_name | _, `Top -> - AnalysisState.svcomp_may_invalid_deref := true; + set_mem_safety_flag InvalidDeref; M.warn ~category:(Behavior behavior) ~tags:[CWE cwe_number] "Count parameter, passed to function %s is unknown. Memory out-of-bounds access might occur" fun_name | `Bot, _ -> - AnalysisState.svcomp_may_invalid_deref := true; + set_mem_safety_flag InvalidDeref; M.warn ~category:(Behavior behavior) ~tags:[CWE cwe_number] "Size of dest %a in function %s is bottom. Memory out-of-bounds access might occur" d_exp dest fun_name | _, `Bot -> + set_mem_safety_flag InvalidDeref; M.warn ~category:(Behavior behavior) ~tags:[CWE cwe_number] "Count parameter, passed to function %s is bottom" fun_name | `Lifted ds, `Lifted en -> let casted_ds = ID.cast_to (Cilfacade.ptrdiff_ikind ()) ds in @@ -389,11 +389,11 @@ struct let dest_size_lt_count = ID.lt casted_ds (ID.add casted_en casted_ao) in begin match ID.to_bool dest_size_lt_count with | Some true -> - AnalysisState.svcomp_may_invalid_deref := true; + set_mem_safety_flag InvalidDeref; M.warn ~category:(Behavior behavior) ~tags:[CWE cwe_number] "Size of dest in function %s is %a (in bytes) with an address offset of %a (in bytes). Count is %a (in bytes). Memory out-of-bounds access must occur" fun_name ID.pretty casted_ds ID.pretty casted_ao ID.pretty casted_en | Some false -> () | None -> - AnalysisState.svcomp_may_invalid_deref := true; + set_mem_safety_flag InvalidDeref; M.warn ~category:(Behavior behavior) ~tags:[CWE cwe_number] "Could not compare size of dest (%a) with address offset (%a) count (%a) in function %s. Memory out-of-bounds access may occur" ID.pretty casted_ds ID.pretty casted_ao ID.pretty casted_en fun_name end diff --git a/src/analyses/useAfterFree.ml b/src/analyses/useAfterFree.ml index dfbab87a29..2f4b54f000 100644 --- a/src/analyses/useAfterFree.ml +++ b/src/analyses/useAfterFree.ml @@ -76,7 +76,7 @@ struct M.warn ~category:(Behavior behavior) ~tags:[CWE cwe_number] "Current thread is not unique and a %s might occur for heap variable %a" bug_name CilType.Varinfo.pretty heap_var end else if HeapVars.mem heap_var (snd ctx.local) then begin - set_global_svcomp_var is_double_free; + if is_double_free then set_mem_safety_flag InvalidFree else set_mem_safety_flag InvalidDeref; M.warn ~category:(Behavior behavior) ~tags:[CWE cwe_number] "%s might occur in current unique thread %a for heap variable %a" bug_name ThreadIdDomain.FlagConfiguredTID.pretty current CilType.Varinfo.pretty heap_var end end @@ -110,8 +110,10 @@ struct begin match ctx.ask (Queries.MayPointTo lval_to_query) with | ad when not (Queries.AD.is_top ad) -> let warn_for_heap_var v = - if HeapVars.mem v (snd state) then + if HeapVars.mem v (snd state) then begin + if is_double_free then set_mem_safety_flag InvalidFree else set_mem_safety_flag InvalidDeref; M.warn ~category:(Behavior undefined_behavior) ~tags:[CWE cwe_number] "lval (%s) in \"%s\" points to a maybe freed memory region" v.vname transfer_fn_name + end in let pointed_to_heap_vars = Queries.AD.fold (fun addr vars -> From da45e40b56d3a049656cfb2993b462e6b797c5ac Mon Sep 17 00:00:00 2001 From: Stanimir Bozhilov Date: Mon, 2 Oct 2023 01:05:18 +0200 Subject: [PATCH 026/140] Clean up UAF analysis a bit --- src/analyses/useAfterFree.ml | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/src/analyses/useAfterFree.ml b/src/analyses/useAfterFree.ml index 2f4b54f000..a28591e273 100644 --- a/src/analyses/useAfterFree.ml +++ b/src/analyses/useAfterFree.ml @@ -15,7 +15,7 @@ module ThreadIdToJoinedThreadsMap = MapDomain.MapBot(ThreadIdDomain.ThreadLifted module Spec : Analyses.MCPSpec = struct - include Analyses.DefaultSpec + include Analyses.IdentitySpec let name () = "useAfterFree" @@ -24,7 +24,6 @@ struct module G = ThreadIdToJoinedThreadsMap module V = VarinfoV - (** TODO: Try out later in benchmarks to see how we perform with and without context-sensititivty *) let context _ _ = () @@ -176,9 +175,6 @@ struct warn_exp_might_contain_freed "branch" ctx exp; ctx.local - let body ctx (f:fundec) : D.t = - ctx.local - let return ctx (exp:exp option) (f:fundec) : D.t = Option.iter (fun x -> warn_exp_might_contain_freed "return" ctx x) exp; ctx.local @@ -248,9 +244,6 @@ struct end | _ -> state - let threadenter ctx lval f args = [ctx.local] - let threadspawn ctx lval f args fctx = ctx.local - let startstate v = D.bot () let exitstate v = D.top () From 1335123d60b556e9759a4e4147d72095142a9452 Mon Sep 17 00:00:00 2001 From: Stanimir Bozhilov Date: Mon, 2 Oct 2023 09:45:49 +0200 Subject: [PATCH 027/140] Recognize mem-safety props in any order --- src/witness/svcompSpec.ml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/witness/svcompSpec.ml b/src/witness/svcompSpec.ml index f066610953..fbe206dabb 100644 --- a/src/witness/svcompSpec.ml +++ b/src/witness/svcompSpec.ml @@ -32,7 +32,8 @@ let of_string s = let global1 = Str.matched_group 1 s in let global2 = Str.matched_group 2 s in let global3 = Str.matched_group 3 s in - if global1 = "valid-free" && global2 = "valid-deref" && global3 = "valid-memtrack" then + let mem_safety_props = ["valid-free"; "valid-deref"; "valid-memtrack";] in + if (global1 <> global2 && global1 <> global3 && global2 <> global3) && List.for_all (fun x -> List.mem x mem_safety_props) [global1; global2; global3] then MemorySafety (* if global = "valid-free" then ValidFree From 1384f733d812996399648b4a846389fcbac29afb Mon Sep 17 00:00:00 2001 From: Stanimir Bozhilov Date: Mon, 2 Oct 2023 09:57:38 +0200 Subject: [PATCH 028/140] Add support for SV-COMP's valid-memcleanup property --- src/autoTune.ml | 1 + src/framework/analysisState.ml | 3 +++ src/util/analysisStateUtil.ml | 4 +++- src/witness/svcomp.ml | 1 + src/witness/svcompSpec.ml | 13 +++++++++++-- src/witness/witness.ml | 30 ++++++++++++++++++++++++++++++ 6 files changed, 49 insertions(+), 3 deletions(-) diff --git a/src/autoTune.ml b/src/autoTune.ml index 9e3508ccd2..ac7c150546 100644 --- a/src/autoTune.ml +++ b/src/autoTune.ml @@ -227,6 +227,7 @@ let focusOnSpecification () = | ValidDeref | ValidMemtrack -> () | MemorySafety -> () (* TODO: This is here for now just to complete the pattern match *) + | ValidMemcleanup -> () (*Detect enumerations and enable the "ana.int.enums" option*) exception EnumFound diff --git a/src/framework/analysisState.ml b/src/framework/analysisState.ml index ca619d4dfb..1416f99f69 100644 --- a/src/framework/analysisState.ml +++ b/src/framework/analysisState.ml @@ -16,6 +16,9 @@ let svcomp_may_invalid_deref = ref false (** Whether an invalid memtrack happened *) let svcomp_may_invalid_memtrack = ref false +(** Whether an invalid memcleanup happened *) +let svcomp_may_invalid_memcleanup = ref false + (** A hack to see if we are currently doing global inits *) let global_initialization = ref false diff --git a/src/util/analysisStateUtil.ml b/src/util/analysisStateUtil.ml index 25914f8c8e..a34be33f18 100644 --- a/src/util/analysisStateUtil.ml +++ b/src/util/analysisStateUtil.ml @@ -2,10 +2,12 @@ type mem_safety_violation = | InvalidFree | InvalidDeref | InvalidMemTrack + | InvalidMemcleanup let set_mem_safety_flag violation_type = if !AnalysisState.postsolving then match violation_type with | InvalidFree -> AnalysisState.svcomp_may_invalid_free := true | InvalidDeref -> AnalysisState.svcomp_may_invalid_deref := true - | InvalidMemTrack -> AnalysisState.svcomp_may_invalid_memtrack := true \ No newline at end of file + | InvalidMemTrack -> AnalysisState.svcomp_may_invalid_memtrack := true + | InvalidMemcleanup -> AnalysisState.svcomp_may_invalid_memcleanup := true \ No newline at end of file diff --git a/src/witness/svcomp.ml b/src/witness/svcomp.ml index 15d41c0210..22543d48a9 100644 --- a/src/witness/svcomp.ml +++ b/src/witness/svcomp.ml @@ -56,6 +56,7 @@ struct | ValidDeref -> "valid-deref" | ValidMemtrack -> "valid-memtrack" | MemorySafety -> "memory-safety" (* TODO: Currently here only to complete the pattern match *) + | ValidMemcleanup -> "valid-memcleanup" in "false(" ^ result_spec ^ ")" | Unknown -> "unknown" diff --git a/src/witness/svcompSpec.ml b/src/witness/svcompSpec.ml index fbe206dabb..25a9f522bc 100644 --- a/src/witness/svcompSpec.ml +++ b/src/witness/svcompSpec.ml @@ -10,10 +10,12 @@ type t = | ValidDeref | ValidMemtrack | MemorySafety (* Internal property for use in Goblint; serves as a summary for ValidFree, ValidDeref and ValidMemtrack *) + | ValidMemcleanup let of_string s = let s = String.strip s in - let regexp = Str.regexp "CHECK( init(main()), LTL(G \\(.*\\)) )\nCHECK( init(main()), LTL(G \\(.*\\)) )\nCHECK( init(main()), LTL(G \\(.*\\)) )" in + let regexp_multiple = Str.regexp "CHECK( init(main()), LTL(G \\(.*\\)) )\nCHECK( init(main()), LTL(G \\(.*\\)) )\nCHECK( init(main()), LTL(G \\(.*\\)) )" in + let regexp_single = Str.regexp "CHECK( init(main()), LTL(G \\(.*\\)) )" in let regexp_negated = Str.regexp "CHECK( init(main()), LTL(G ! \\(.*\\)) )" in if Str.string_match regexp_negated s 0 then let global_not = Str.matched_group 1 s in @@ -28,7 +30,7 @@ let of_string s = UnreachCall f else failwith "Svcomp.Specification.of_string: unknown global not expression" - else if Str.string_match regexp s 0 then + else if Str.string_match regexp_multiple s 0 then let global1 = Str.matched_group 1 s in let global2 = Str.matched_group 2 s in let global3 = Str.matched_group 3 s in @@ -43,6 +45,12 @@ let of_string s = ValidMemtrack *) else failwith "Svcomp.Specification.of_string: unknown global expression" + else if Str.string_match regexp_single s 0 then + let global = Str.matched_group 1 s in + if global = "valid-memcleanup" then + ValidMemcleanup + else + failwith "Svcomp.Specification.of_string: unknown global expression" else failwith "Svcomp.Specification.of_string: unknown expression" @@ -72,5 +80,6 @@ let to_string spec = | ValidDeref -> "valid-deref", false | ValidMemtrack -> "valid-memtrack", false | MemorySafety -> "memory-safety", false (* TODO: That's false, it's currently here just to complete the pattern match *) + | ValidMemcleanup -> "valid-memcleanup", false in print_output spec_str is_neg diff --git a/src/witness/witness.ml b/src/witness/witness.ml index 17dd14472e..35d932210d 100644 --- a/src/witness/witness.ml +++ b/src/witness/witness.ml @@ -625,6 +625,36 @@ struct in (module TaskResult:WitnessTaskResult) ) + | ValidMemcleanup -> + let module TrivialArg = + struct + include Arg + let next _ = [] + end + in + if not !AnalysisState.svcomp_may_invalid_memcleanup then ( + let module TaskResult = + struct + module Arg = Arg + let result = Result.True + let invariant _ = Invariant.none + let is_violation _ = false + let is_sink _ = false + end + in + (module TaskResult:WitnessTaskResult) + ) else ( + let module TaskResult = + struct + module Arg = TrivialArg + let result = Result.Unknown + let invariant _ = Invariant.none + let is_violation _ = false + let is_sink _ = false + end + in + (module TaskResult:WitnessTaskResult) + ) let write entrystates = From 4e70422c2c305de6408ef68177dddb1f3c9e9833 Mon Sep 17 00:00:00 2001 From: Stanimir Bozhilov Date: Mon, 2 Oct 2023 09:59:08 +0200 Subject: [PATCH 029/140] Set SV-COMP global flag for invalid-memcleanup --- src/analyses/memLeak.ml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/analyses/memLeak.ml b/src/analyses/memLeak.ml index eb38b97a1c..dbaa2d69fc 100644 --- a/src/analyses/memLeak.ml +++ b/src/analyses/memLeak.ml @@ -22,6 +22,7 @@ struct let warn_for_multi_threaded ctx = if not (ctx.ask (Queries.MustBeSingleThreaded { since_start = true })) then ( set_mem_safety_flag InvalidMemTrack; + set_mem_safety_flag InvalidMemcleanup; M.warn ~category:(Behavior (Undefined MemoryLeak)) ~tags:[CWE 401] "Program isn't running in single-threaded mode. A memory leak might occur due to multi-threading" ) @@ -31,9 +32,11 @@ struct match assert_exp_imprecise, exp with | true, Some exp -> set_mem_safety_flag InvalidMemTrack; + set_mem_safety_flag InvalidMemcleanup; M.warn ~category:(Behavior (Undefined MemoryLeak)) ~tags:[CWE 401] "assert expression %a is unknown. Memory leak might possibly occur for heap variables: %a" d_exp exp D.pretty state | _ -> set_mem_safety_flag InvalidMemTrack; + set_mem_safety_flag InvalidMemcleanup; M.warn ~category:(Behavior (Undefined MemoryLeak)) ~tags:[CWE 401] "Memory leak detected for heap variables: %a" D.pretty state (* TRANSFER FUNCTIONS *) From 00cc9b541ae6e6270906c16cbba94498692ab6f3 Mon Sep 17 00:00:00 2001 From: Stanimir Bozhilov Date: Mon, 2 Oct 2023 10:58:45 +0200 Subject: [PATCH 030/140] Enable memory safety analyses in autoTune --- src/autoTune.ml | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/src/autoTune.ml b/src/autoTune.ml index ac7c150546..f73a71ed40 100644 --- a/src/autoTune.ml +++ b/src/autoTune.ml @@ -223,11 +223,18 @@ let focusOnSpecification () = let uafAna = ["useAfterFree"] in print_endline @@ "Specification: ValidFree -> enabling useAfterFree analysis \"" ^ (String.concat ", " uafAna) ^ "\""; enableAnalyses uafAna - (* TODO: Finish these two below later *) - | ValidDeref - | ValidMemtrack -> () - | MemorySafety -> () (* TODO: This is here for now just to complete the pattern match *) - | ValidMemcleanup -> () + | ValidDeref -> (* Enable the memOutOfBounds analysis *) + let memOobAna = ["memOutOfBounds"] in + print_endline @@ "Specification: ValidDeref -> enabling memOutOfBounds analysis \"" ^ (String.concat ", " memOobAna) ^ "\""; + enableAnalyses memOobAna + | ValidMemtrack + | ValidMemcleanup -> (* Enable the memLeak analysis *) + let memLeakAna = ["memLeak"] in + print_endline @@ "Specification: ValidDeref and ValidMemcleanup -> enabling memLeak analysis \"" ^ (String.concat ", " memLeakAna) ^ "\""; + enableAnalyses memLeakAna + | MemorySafety -> (* TODO: This is a temporary solution for the memory safety category *) + let memSafetyAnas = ["memOutOfBounds"; "memLeak"; "useAfterFree";] in + enableAnalyses memSafetyAnas (*Detect enumerations and enable the "ana.int.enums" option*) exception EnumFound From 2c8e927f4e5f88b0a4eb003da6fd24ac55a0e004 Mon Sep 17 00:00:00 2001 From: Stanimir Bozhilov Date: Mon, 2 Oct 2023 10:59:36 +0200 Subject: [PATCH 031/140] Rename UAF tests from number 78 to 74 --- .../{78-use_after_free => 74-use_after_free}/01-simple-uaf.c | 0 .../{78-use_after_free => 74-use_after_free}/02-conditional-uaf.c | 0 .../{78-use_after_free => 74-use_after_free}/03-nested-ptr-uaf.c | 0 .../04-function-call-uaf.c | 0 .../05-uaf-free-in-wrapper-fun.c | 0 .../{78-use_after_free => 74-use_after_free}/06-uaf-struct.c | 0 .../{78-use_after_free => 74-use_after_free}/07-itc-double-free.c | 0 .../08-itc-no-double-free.c | 0 .../{78-use_after_free => 74-use_after_free}/09-juliet-uaf.c | 0 .../10-juliet-double-free.c | 0 .../11-wrapper-funs-uaf.c | 0 .../12-multi-threaded-uaf.c | 0 .../13-multi-threaded-uaf-with-joined-thread.c | 0 .../{78-use_after_free => 74-use_after_free}/14-alloca-uaf.c | 0 14 files changed, 0 insertions(+), 0 deletions(-) rename tests/regression/{78-use_after_free => 74-use_after_free}/01-simple-uaf.c (100%) rename tests/regression/{78-use_after_free => 74-use_after_free}/02-conditional-uaf.c (100%) rename tests/regression/{78-use_after_free => 74-use_after_free}/03-nested-ptr-uaf.c (100%) rename tests/regression/{78-use_after_free => 74-use_after_free}/04-function-call-uaf.c (100%) rename tests/regression/{78-use_after_free => 74-use_after_free}/05-uaf-free-in-wrapper-fun.c (100%) rename tests/regression/{78-use_after_free => 74-use_after_free}/06-uaf-struct.c (100%) rename tests/regression/{78-use_after_free => 74-use_after_free}/07-itc-double-free.c (100%) rename tests/regression/{78-use_after_free => 74-use_after_free}/08-itc-no-double-free.c (100%) rename tests/regression/{78-use_after_free => 74-use_after_free}/09-juliet-uaf.c (100%) rename tests/regression/{78-use_after_free => 74-use_after_free}/10-juliet-double-free.c (100%) rename tests/regression/{78-use_after_free => 74-use_after_free}/11-wrapper-funs-uaf.c (100%) rename tests/regression/{78-use_after_free => 74-use_after_free}/12-multi-threaded-uaf.c (100%) rename tests/regression/{78-use_after_free => 74-use_after_free}/13-multi-threaded-uaf-with-joined-thread.c (100%) rename tests/regression/{78-use_after_free => 74-use_after_free}/14-alloca-uaf.c (100%) diff --git a/tests/regression/78-use_after_free/01-simple-uaf.c b/tests/regression/74-use_after_free/01-simple-uaf.c similarity index 100% rename from tests/regression/78-use_after_free/01-simple-uaf.c rename to tests/regression/74-use_after_free/01-simple-uaf.c diff --git a/tests/regression/78-use_after_free/02-conditional-uaf.c b/tests/regression/74-use_after_free/02-conditional-uaf.c similarity index 100% rename from tests/regression/78-use_after_free/02-conditional-uaf.c rename to tests/regression/74-use_after_free/02-conditional-uaf.c diff --git a/tests/regression/78-use_after_free/03-nested-ptr-uaf.c b/tests/regression/74-use_after_free/03-nested-ptr-uaf.c similarity index 100% rename from tests/regression/78-use_after_free/03-nested-ptr-uaf.c rename to tests/regression/74-use_after_free/03-nested-ptr-uaf.c diff --git a/tests/regression/78-use_after_free/04-function-call-uaf.c b/tests/regression/74-use_after_free/04-function-call-uaf.c similarity index 100% rename from tests/regression/78-use_after_free/04-function-call-uaf.c rename to tests/regression/74-use_after_free/04-function-call-uaf.c diff --git a/tests/regression/78-use_after_free/05-uaf-free-in-wrapper-fun.c b/tests/regression/74-use_after_free/05-uaf-free-in-wrapper-fun.c similarity index 100% rename from tests/regression/78-use_after_free/05-uaf-free-in-wrapper-fun.c rename to tests/regression/74-use_after_free/05-uaf-free-in-wrapper-fun.c diff --git a/tests/regression/78-use_after_free/06-uaf-struct.c b/tests/regression/74-use_after_free/06-uaf-struct.c similarity index 100% rename from tests/regression/78-use_after_free/06-uaf-struct.c rename to tests/regression/74-use_after_free/06-uaf-struct.c diff --git a/tests/regression/78-use_after_free/07-itc-double-free.c b/tests/regression/74-use_after_free/07-itc-double-free.c similarity index 100% rename from tests/regression/78-use_after_free/07-itc-double-free.c rename to tests/regression/74-use_after_free/07-itc-double-free.c diff --git a/tests/regression/78-use_after_free/08-itc-no-double-free.c b/tests/regression/74-use_after_free/08-itc-no-double-free.c similarity index 100% rename from tests/regression/78-use_after_free/08-itc-no-double-free.c rename to tests/regression/74-use_after_free/08-itc-no-double-free.c diff --git a/tests/regression/78-use_after_free/09-juliet-uaf.c b/tests/regression/74-use_after_free/09-juliet-uaf.c similarity index 100% rename from tests/regression/78-use_after_free/09-juliet-uaf.c rename to tests/regression/74-use_after_free/09-juliet-uaf.c diff --git a/tests/regression/78-use_after_free/10-juliet-double-free.c b/tests/regression/74-use_after_free/10-juliet-double-free.c similarity index 100% rename from tests/regression/78-use_after_free/10-juliet-double-free.c rename to tests/regression/74-use_after_free/10-juliet-double-free.c diff --git a/tests/regression/78-use_after_free/11-wrapper-funs-uaf.c b/tests/regression/74-use_after_free/11-wrapper-funs-uaf.c similarity index 100% rename from tests/regression/78-use_after_free/11-wrapper-funs-uaf.c rename to tests/regression/74-use_after_free/11-wrapper-funs-uaf.c diff --git a/tests/regression/78-use_after_free/12-multi-threaded-uaf.c b/tests/regression/74-use_after_free/12-multi-threaded-uaf.c similarity index 100% rename from tests/regression/78-use_after_free/12-multi-threaded-uaf.c rename to tests/regression/74-use_after_free/12-multi-threaded-uaf.c diff --git a/tests/regression/78-use_after_free/13-multi-threaded-uaf-with-joined-thread.c b/tests/regression/74-use_after_free/13-multi-threaded-uaf-with-joined-thread.c similarity index 100% rename from tests/regression/78-use_after_free/13-multi-threaded-uaf-with-joined-thread.c rename to tests/regression/74-use_after_free/13-multi-threaded-uaf-with-joined-thread.c diff --git a/tests/regression/78-use_after_free/14-alloca-uaf.c b/tests/regression/74-use_after_free/14-alloca-uaf.c similarity index 100% rename from tests/regression/78-use_after_free/14-alloca-uaf.c rename to tests/regression/74-use_after_free/14-alloca-uaf.c From f87285462b6cdcff1a2081b0d80b266ce248a358 Mon Sep 17 00:00:00 2001 From: Stanimir Bozhilov Date: Tue, 3 Oct 2023 12:57:44 +0300 Subject: [PATCH 032/140] Fix print for valid-memtrack and valid-memcleanup in `autoTune.ml` Co-authored-by: Michael Schwarz --- src/autoTune.ml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/autoTune.ml b/src/autoTune.ml index f73a71ed40..e093c63f08 100644 --- a/src/autoTune.ml +++ b/src/autoTune.ml @@ -230,7 +230,7 @@ let focusOnSpecification () = | ValidMemtrack | ValidMemcleanup -> (* Enable the memLeak analysis *) let memLeakAna = ["memLeak"] in - print_endline @@ "Specification: ValidDeref and ValidMemcleanup -> enabling memLeak analysis \"" ^ (String.concat ", " memLeakAna) ^ "\""; + print_endline @@ "Specification: ValidMemtrack and ValidMemcleanup -> enabling memLeak analysis \"" ^ (String.concat ", " memLeakAna) ^ "\""; enableAnalyses memLeakAna | MemorySafety -> (* TODO: This is a temporary solution for the memory safety category *) let memSafetyAnas = ["memOutOfBounds"; "memLeak"; "useAfterFree";] in From edaef4230d6db75def47f41b4a748c9cbd5aa83d Mon Sep 17 00:00:00 2001 From: Stanimir Bozhilov Date: Tue, 3 Oct 2023 12:02:01 +0200 Subject: [PATCH 033/140] Set `ana.malloc.unique_address_count` to `1` when activating memLeak analysis --- src/autoTune.ml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/autoTune.ml b/src/autoTune.ml index e093c63f08..0441fe0b4f 100644 --- a/src/autoTune.ml +++ b/src/autoTune.ml @@ -230,6 +230,8 @@ let focusOnSpecification () = | ValidMemtrack | ValidMemcleanup -> (* Enable the memLeak analysis *) let memLeakAna = ["memLeak"] in + print_endline "Setting \"ana.malloc.unique_address_count\" to 1"; + set_int "ana.malloc.unique_address_count" 1; print_endline @@ "Specification: ValidMemtrack and ValidMemcleanup -> enabling memLeak analysis \"" ^ (String.concat ", " memLeakAna) ^ "\""; enableAnalyses memLeakAna | MemorySafety -> (* TODO: This is a temporary solution for the memory safety category *) From 7f0b43ccf1db2d6c3bec95ce1ea759dff84e4fba Mon Sep 17 00:00:00 2001 From: Stanimir Bozhilov Date: Tue, 3 Oct 2023 12:09:00 +0200 Subject: [PATCH 034/140] Improve some `AnalysisState` global flag comments --- src/framework/analysisState.ml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/framework/analysisState.ml b/src/framework/analysisState.ml index 1416f99f69..05a93741f8 100644 --- a/src/framework/analysisState.ml +++ b/src/framework/analysisState.ml @@ -13,10 +13,10 @@ let svcomp_may_invalid_free = ref false (** Whether an invalid pointer dereference happened *) let svcomp_may_invalid_deref = ref false -(** Whether an invalid memtrack happened *) +(** Whether a memory leak occurred and there's no reference to the leaked memory *) let svcomp_may_invalid_memtrack = ref false -(** Whether an invalid memcleanup happened *) +(** Whether a memory leak occurred *) let svcomp_may_invalid_memcleanup = ref false (** A hack to see if we are currently doing global inits *) From a975702f700511c3c1f0b71979502462192d9bc2 Mon Sep 17 00:00:00 2001 From: Stanimir Bozhilov Date: Tue, 3 Oct 2023 12:25:33 +0200 Subject: [PATCH 035/140] Clean up some commented out code --- src/witness/svcompSpec.ml | 6 --- src/witness/witness.ml | 93 ++------------------------------------- 2 files changed, 3 insertions(+), 96 deletions(-) diff --git a/src/witness/svcompSpec.ml b/src/witness/svcompSpec.ml index 25a9f522bc..4a3da23d9b 100644 --- a/src/witness/svcompSpec.ml +++ b/src/witness/svcompSpec.ml @@ -37,12 +37,6 @@ let of_string s = let mem_safety_props = ["valid-free"; "valid-deref"; "valid-memtrack";] in if (global1 <> global2 && global1 <> global3 && global2 <> global3) && List.for_all (fun x -> List.mem x mem_safety_props) [global1; global2; global3] then MemorySafety - (* if global = "valid-free" then - ValidFree - else if global = "valid-deref" then - ValidDeref - else if global = "valid-memtrack" then - ValidMemtrack *) else failwith "Svcomp.Specification.of_string: unknown global expression" else if Str.string_match regexp_single s 0 then diff --git a/src/witness/witness.ml b/src/witness/witness.ml index 35d932210d..a28f69f76a 100644 --- a/src/witness/witness.ml +++ b/src/witness/witness.ml @@ -505,96 +505,9 @@ struct in (module TaskResult:WitnessTaskResult) ) - | ValidFree (*->*) - (* let module TrivialArg = - struct - include Arg - let next _ = [] - end - in - if not !AnalysisState.svcomp_may_invalid_free then ( - let module TaskResult = - struct - module Arg = Arg - let result = Result.True - let invariant _ = Invariant.none - let is_violation _ = false - let is_sink _ = false - end - in - (module TaskResult:WitnessTaskResult) - ) else ( - let module TaskResult = - struct - module Arg = TrivialArg - let result = Result.Unknown - let invariant _ = Invariant.none - let is_violation _ = false - let is_sink _ = false - end - in - (module TaskResult:WitnessTaskResult) - ) *) - | ValidDeref (*->*) - (* let module TrivialArg = - struct - include Arg - let next _ = [] - end - in - if not !AnalysisState.svcomp_may_invalid_deref then ( - let module TaskResult = - struct - module Arg = Arg - let result = Result.True - let invariant _ = Invariant.none - let is_violation _ = false - let is_sink _ = false - end - in - (module TaskResult:WitnessTaskResult) - ) else ( - let module TaskResult = - struct - module Arg = TrivialArg - let result = Result.Unknown - let invariant _ = Invariant.none - let is_violation _ = false - let is_sink _ = false - end - in - (module TaskResult:WitnessTaskResult) - ) *) - | ValidMemtrack (*->*) - (* let module TrivialArg = - struct - include Arg - let next _ = [] - end - in - if not !AnalysisState.svcomp_may_invalid_memtrack then ( - let module TaskResult = - struct - module Arg = Arg - let result = Result.True - let invariant _ = Invariant.none - let is_violation _ = false - let is_sink _ = false - end - in - (module TaskResult:WitnessTaskResult) - ) else ( - let module TaskResult = - struct - module Arg = TrivialArg - let result = Result.Unknown - let invariant _ = Invariant.none - let is_violation _ = false - let is_sink _ = false - end - in - (module TaskResult:WitnessTaskResult) - ) *) + | ValidFree + | ValidDeref + | ValidMemtrack | MemorySafety -> let module TrivialArg = struct From b26010ac042143b4cdeb806b2a35b67054db1d76 Mon Sep 17 00:00:00 2001 From: Stanimir Bozhilov Date: Tue, 3 Oct 2023 12:31:31 +0200 Subject: [PATCH 036/140] Set `ana.malloc.unique_address_count` to `1` only if it's not already set to a value >= 1 --- src/autoTune.ml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/autoTune.ml b/src/autoTune.ml index 0441fe0b4f..4912d645ce 100644 --- a/src/autoTune.ml +++ b/src/autoTune.ml @@ -230,8 +230,10 @@ let focusOnSpecification () = | ValidMemtrack | ValidMemcleanup -> (* Enable the memLeak analysis *) let memLeakAna = ["memLeak"] in - print_endline "Setting \"ana.malloc.unique_address_count\" to 1"; - set_int "ana.malloc.unique_address_count" 1; + if (get_int "ana.malloc.unique_address_count") < 1 then ( + print_endline "Setting \"ana.malloc.unique_address_count\" to 1"; + set_int "ana.malloc.unique_address_count" 1; + ); print_endline @@ "Specification: ValidMemtrack and ValidMemcleanup -> enabling memLeak analysis \"" ^ (String.concat ", " memLeakAna) ^ "\""; enableAnalyses memLeakAna | MemorySafety -> (* TODO: This is a temporary solution for the memory safety category *) From 89d68af6d7c68a647e13dd77e876580dbc8e71b1 Mon Sep 17 00:00:00 2001 From: Stanimir Bozhilov Date: Tue, 3 Oct 2023 12:35:30 +0200 Subject: [PATCH 037/140] Add a valid-memcleanup.prp file --- tests/sv-comp/valid-memcleanup.prp | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 tests/sv-comp/valid-memcleanup.prp diff --git a/tests/sv-comp/valid-memcleanup.prp b/tests/sv-comp/valid-memcleanup.prp new file mode 100644 index 0000000000..778c49e5dc --- /dev/null +++ b/tests/sv-comp/valid-memcleanup.prp @@ -0,0 +1,2 @@ +CHECK( init(main()), LTL(G valid-memcleanup) ) + From 171ba57b315044c20252fbff625a652c0f2d328f Mon Sep 17 00:00:00 2001 From: Stanimir Bozhilov Date: Tue, 3 Oct 2023 15:13:00 +0200 Subject: [PATCH 038/140] Comment out reachability filter in useAfterFree's `enter` --- src/analyses/useAfterFree.ml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/analyses/useAfterFree.ml b/src/analyses/useAfterFree.ml index a28591e273..805bf1792c 100644 --- a/src/analyses/useAfterFree.ml +++ b/src/analyses/useAfterFree.ml @@ -182,7 +182,8 @@ struct let enter ctx (lval:lval option) (f:fundec) (args:exp list) : (D.t * D.t) list = let caller_state = ctx.local in List.iter (fun arg -> warn_exp_might_contain_freed "enter" ctx arg) args; - if AllocaVars.is_empty (fst caller_state) && HeapVars.is_empty (snd caller_state) then + [(caller_state, caller_state)] + (* if AllocaVars.is_empty (fst caller_state) && HeapVars.is_empty (snd caller_state) then [caller_state, caller_state] else ( let reachable_from_args = List.fold_left (fun ad arg -> Queries.AD.join ad (ctx.ask (ReachableFrom arg))) (Queries.AD.empty ()) args in @@ -192,7 +193,7 @@ struct let reachable_vars = Queries.AD.to_var_may reachable_from_args in let callee_state = (AllocaVars.empty (), HeapVars.filter (fun var -> List.mem var reachable_vars) (snd caller_state)) in (* TODO: use AD.mem directly *) [caller_state, callee_state] - ) + ) *) let combine_env ctx (lval:lval option) fexp (f:fundec) (args:exp list) fc (callee_local:D.t) (f_ask:Queries.ask) : D.t = let (caller_stack_state, caller_heap_state) = ctx.local in From 4a1c038b5bd32674b8dff3bd9499d4a6ddbb2f85 Mon Sep 17 00:00:00 2001 From: Stanimir Bozhilov Date: Tue, 3 Oct 2023 15:25:31 +0200 Subject: [PATCH 039/140] Fix wrong callee_state in enter --- src/analyses/useAfterFree.ml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/analyses/useAfterFree.ml b/src/analyses/useAfterFree.ml index 805bf1792c..521f17d97f 100644 --- a/src/analyses/useAfterFree.ml +++ b/src/analyses/useAfterFree.ml @@ -182,7 +182,7 @@ struct let enter ctx (lval:lval option) (f:fundec) (args:exp list) : (D.t * D.t) list = let caller_state = ctx.local in List.iter (fun arg -> warn_exp_might_contain_freed "enter" ctx arg) args; - [(caller_state, caller_state)] + [caller_state, (AllocaVars.empty (), snd caller_state)] (* if AllocaVars.is_empty (fst caller_state) && HeapVars.is_empty (snd caller_state) then [caller_state, caller_state] else ( From bb2091e5038a437c23db3c8711d38f19a301ef05 Mon Sep 17 00:00:00 2001 From: Stanimir Bozhilov Date: Tue, 3 Oct 2023 15:25:45 +0200 Subject: [PATCH 040/140] Add test case for UAF in callee through a global var --- .../15-juliet-uaf-global-var.c | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 tests/regression/74-use_after_free/15-juliet-uaf-global-var.c diff --git a/tests/regression/74-use_after_free/15-juliet-uaf-global-var.c b/tests/regression/74-use_after_free/15-juliet-uaf-global-var.c new file mode 100644 index 0000000000..9cb3b2b29a --- /dev/null +++ b/tests/regression/74-use_after_free/15-juliet-uaf-global-var.c @@ -0,0 +1,24 @@ +//PARAM: --set ana.activated[+] useAfterFree --set ana.activated[+] threadJoins +#include +#include +#include + +int *global; + +void other(void) +{ + int *data = global; + free((void *)data); + return; +} + +int main(int argc, char **argv) +{ + int *data = (int *)malloc(400UL); + free((void *)data); + + global = data; + other(); + + return 0; +} \ No newline at end of file From fb4ad24d4f71f93181c3b908398bc785c5c32dfe Mon Sep 17 00:00:00 2001 From: Stanimir Bozhilov Date: Tue, 3 Oct 2023 16:32:48 +0200 Subject: [PATCH 041/140] Fix typo for warning about top address offsets --- src/analyses/memOutOfBounds.ml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/analyses/memOutOfBounds.ml b/src/analyses/memOutOfBounds.ml index db86a63414..ca2cf82116 100644 --- a/src/analyses/memOutOfBounds.ml +++ b/src/analyses/memOutOfBounds.ml @@ -205,7 +205,7 @@ struct set_mem_safety_flag InvalidDeref; M.warn "Pointer %a has a bot address offset. An invalid memory access may occur" d_exp ptr ) else if VDQ.AD.exists (function - | Addr (_, o) -> ID.is_bot @@ offs_to_idx t o + | Addr (_, o) -> ID.is_top_of (Cilfacade.ptrdiff_ikind ()) (offs_to_idx t o) | _ -> false ) a then ( set_mem_safety_flag InvalidDeref; From 9d64db11a69abf60b0c777ee591860416c49666d Mon Sep 17 00:00:00 2001 From: Stanimir Bozhilov Date: Tue, 3 Oct 2023 16:33:09 +0200 Subject: [PATCH 042/140] Add test case with invalid deref in complex loop --- .../regression/77-mem-oob/10-oob-two-loops.c | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 tests/regression/77-mem-oob/10-oob-two-loops.c diff --git a/tests/regression/77-mem-oob/10-oob-two-loops.c b/tests/regression/77-mem-oob/10-oob-two-loops.c new file mode 100644 index 0000000000..2661f3dff7 --- /dev/null +++ b/tests/regression/77-mem-oob/10-oob-two-loops.c @@ -0,0 +1,20 @@ +// PARAM: --set ana.activated[+] memOutOfBounds --enable ana.int.interval +int main() { + int *p = malloc(1048 * sizeof(int)); + + for (int i = 0; i < 1048; ++i) { + p[i] = __VERIFIER_nondet_int(); //NOWARN + } + + int *q = p; + + while (*q >= 0 && q < p + 1048 * sizeof(int)) { //WARN + if (__VERIFIER_nondet_int()) { + q++; + } else { + (*q)--; //WARN + } + } + free(p); + return 0; +} From 1afac024c34280a8c1b6bfbeae254654800d5919 Mon Sep 17 00:00:00 2001 From: Stanimir Bozhilov Date: Tue, 3 Oct 2023 16:39:30 +0200 Subject: [PATCH 043/140] Disable info messages which confuse `make test` in 77/10 --- tests/regression/77-mem-oob/10-oob-two-loops.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/regression/77-mem-oob/10-oob-two-loops.c b/tests/regression/77-mem-oob/10-oob-two-loops.c index 2661f3dff7..6737a212bf 100644 --- a/tests/regression/77-mem-oob/10-oob-two-loops.c +++ b/tests/regression/77-mem-oob/10-oob-two-loops.c @@ -1,4 +1,4 @@ -// PARAM: --set ana.activated[+] memOutOfBounds --enable ana.int.interval +// PARAM: --set ana.activated[+] memOutOfBounds --enable ana.int.interval --disable warn.info int main() { int *p = malloc(1048 * sizeof(int)); From f5c197e119e44fa997022daebaaae98d8e07ecf0 Mon Sep 17 00:00:00 2001 From: Stanimir Bozhilov Date: Tue, 3 Oct 2023 17:28:47 +0200 Subject: [PATCH 044/140] Add option for enabling the marking of variables as pulled out of scope --- src/util/cilfacade.ml | 4 +++- src/util/options.schema.json | 6 ++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/util/cilfacade.ml b/src/util/cilfacade.ml index eb7330aa19..32b6627319 100644 --- a/src/util/cilfacade.ml +++ b/src/util/cilfacade.ml @@ -51,7 +51,9 @@ let init () = (* lineDirectiveStyle := None; *) RmUnused.keepUnused := true; print_CIL_Input := true; - Cabs2cil.allowDuplication := false + Cabs2cil.allowDuplication := false; + if get_bool "cil.addNestedScopeAttr" then + Cabs2cil.addNestedScopeAttr := true let current_file = ref dummyFile diff --git a/src/util/options.schema.json b/src/util/options.schema.json index 1b9c7d3fd5..400dde06dc 100644 --- a/src/util/options.schema.json +++ b/src/util/options.schema.json @@ -288,6 +288,12 @@ "type": "boolean", "description": "Indicates whether gnu89 semantic should be used for inline functions.", "default": false + }, + "addNestedScopeAttr": { + "title": "cil.addNestedScopeAttr", + "type": "boolean", + "description": "Indicates whether variables that CIL pulls out of their scope should be marked.", + "default": false } }, "additionalProperties": false From 003b8148f3cb5035f083ee8c8e3ab339b3d9538e Mon Sep 17 00:00:00 2001 From: Stanimir Bozhilov Date: Tue, 3 Oct 2023 17:29:17 +0200 Subject: [PATCH 045/140] Warn for accesses to variables pulled out of scope --- src/analyses/memOutOfBounds.ml | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/analyses/memOutOfBounds.ml b/src/analyses/memOutOfBounds.ml index ca2cf82116..9db6e58e5f 100644 --- a/src/analyses/memOutOfBounds.ml +++ b/src/analyses/memOutOfBounds.ml @@ -228,6 +228,7 @@ struct ID.top_of @@ Cilfacade.ptrdiff_ikind () and check_lval_for_oob_access ctx ?(is_implicitly_derefed = false) lval = + check_lval_out_of_scope_access lval; (* If the lval does not contain a pointer or if it does contain a pointer, but only points to string addresses, then no need to WARN *) if (not @@ lval_contains_a_ptr lval) || ptr_only_has_str_addr ctx (Lval lval) then () else @@ -246,6 +247,15 @@ struct | _ -> check_exp_for_oob_access ctx ~is_implicitly_derefed e end + and check_lval_out_of_scope_access lval = + match lval with + | (Var v, _) -> + if hasAttribute "goblint_cil_nested" v.vattr then ( + set_mem_safety_flag InvalidDeref; + M.warn "Lvalue %a is potentially accessed out-of-scope. Invalid memory access may occur" d_lval lval + ) + | _ -> () + and check_no_binop_deref ctx lval_exp = check_unknown_addr_deref ctx lval_exp; let behavior = Undefined MemoryOutOfBoundsAccess in From ac7dd717c0dc8f353130c1395dc0f7910aaf8f24 Mon Sep 17 00:00:00 2001 From: Stanimir Bozhilov Date: Tue, 3 Oct 2023 17:29:44 +0200 Subject: [PATCH 046/140] Automatically set `cil.addNestedScopeAttr` in autoTune when running `memOutOfBounds` --- src/autoTune.ml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/autoTune.ml b/src/autoTune.ml index 4912d645ce..4e0080d0bd 100644 --- a/src/autoTune.ml +++ b/src/autoTune.ml @@ -225,6 +225,8 @@ let focusOnSpecification () = enableAnalyses uafAna | ValidDeref -> (* Enable the memOutOfBounds analysis *) let memOobAna = ["memOutOfBounds"] in + print_endline "Setting \"cil.addNestedScopeAttr\" to true"; + set_bool "cil.addNestedScopeAttr" true; print_endline @@ "Specification: ValidDeref -> enabling memOutOfBounds analysis \"" ^ (String.concat ", " memOobAna) ^ "\""; enableAnalyses memOobAna | ValidMemtrack From c95a846617c7a73c86d5a2e4655b5e0f16d4f32e Mon Sep 17 00:00:00 2001 From: Stanimir Bozhilov Date: Tue, 3 Oct 2023 17:59:18 +0200 Subject: [PATCH 047/140] Bump goblint-cil --- goblint.opam | 6 +++--- goblint.opam.locked | 3 +++ goblint.opam.template | 6 +++--- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/goblint.opam b/goblint.opam index 661222805b..88289820c1 100644 --- a/goblint.opam +++ b/goblint.opam @@ -74,12 +74,12 @@ dev-repo: "git+https://github.com/goblint/analyzer.git" # on `dune build` goblint.opam will be generated from goblint.opam.template and dune-project # also remember to generate/adjust goblint.opam.locked! available: os-distribution != "alpine" & arch != "arm64" -# pin-depends: [ +pin-depends: [ # published goblint-cil 2.0.2 is currently up-to-date, so no pin needed - # [ "goblint-cil.2.0.2" "git+https://github.com/goblint/cil.git#98598d94f796a63751e5a9d39c6b3a9fe1f32330" ] + [ "goblint-cil.2.0.2" "git+https://github.com/goblint/cil.git#c7ffc37ad83216a84d90fdbf427cc02a68ea5331" ] # TODO: add back after release, only pinned for optimization (https://github.com/ocaml-ppx/ppx_deriving/pull/252) # [ "ppx_deriving.5.2.1" "git+https://github.com/ocaml-ppx/ppx_deriving.git#0a89b619f94cbbfc3b0fb3255ab4fe5bc77d32d6" ] -# ] +] post-messages: [ "Do not benchmark Goblint on OCaml 5 (https://goblint.readthedocs.io/en/latest/user-guide/benchmarking/)." {ocaml:version >= "5.0.0"} ] diff --git a/goblint.opam.locked b/goblint.opam.locked index bb59c41dd1..31acfdd4ea 100644 --- a/goblint.opam.locked +++ b/goblint.opam.locked @@ -122,6 +122,9 @@ build: [ ] dev-repo: "git+https://github.com/goblint/analyzer.git" available: os-distribution != "alpine" & arch != "arm64" +pin-depends: [ + [ "goblint-cil.2.0.2" "git+https://github.com/goblint/cil.git#c7ffc37ad83216a84d90fdbf427cc02a68ea5331" ] +] conflicts: [ "result" {< "1.5"} ] diff --git a/goblint.opam.template b/goblint.opam.template index 6259c4d498..3476f5befe 100644 --- a/goblint.opam.template +++ b/goblint.opam.template @@ -1,12 +1,12 @@ # on `dune build` goblint.opam will be generated from goblint.opam.template and dune-project # also remember to generate/adjust goblint.opam.locked! available: os-distribution != "alpine" & arch != "arm64" -# pin-depends: [ +pin-depends: [ # published goblint-cil 2.0.2 is currently up-to-date, so no pin needed - # [ "goblint-cil.2.0.2" "git+https://github.com/goblint/cil.git#98598d94f796a63751e5a9d39c6b3a9fe1f32330" ] + [ "goblint-cil.2.0.2" "git+https://github.com/goblint/cil.git#c7ffc37ad83216a84d90fdbf427cc02a68ea5331" ] # TODO: add back after release, only pinned for optimization (https://github.com/ocaml-ppx/ppx_deriving/pull/252) # [ "ppx_deriving.5.2.1" "git+https://github.com/ocaml-ppx/ppx_deriving.git#0a89b619f94cbbfc3b0fb3255ab4fe5bc77d32d6" ] -# ] +] post-messages: [ "Do not benchmark Goblint on OCaml 5 (https://goblint.readthedocs.io/en/latest/user-guide/benchmarking/)." {ocaml:version >= "5.0.0"} ] From c9a846b6a74f1dd37f53d15d9909adb291ec82da Mon Sep 17 00:00:00 2001 From: Michael Schwarz Date: Tue, 3 Oct 2023 18:48:01 +0200 Subject: [PATCH 048/140] set also for meta property --- src/autoTune.ml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/autoTune.ml b/src/autoTune.ml index 4e0080d0bd..10c9570d46 100644 --- a/src/autoTune.ml +++ b/src/autoTune.ml @@ -239,8 +239,10 @@ let focusOnSpecification () = print_endline @@ "Specification: ValidMemtrack and ValidMemcleanup -> enabling memLeak analysis \"" ^ (String.concat ", " memLeakAna) ^ "\""; enableAnalyses memLeakAna | MemorySafety -> (* TODO: This is a temporary solution for the memory safety category *) - let memSafetyAnas = ["memOutOfBounds"; "memLeak"; "useAfterFree";] in - enableAnalyses memSafetyAnas + (print_endline "Setting \"cil.addNestedScopeAttr\" to true"; + set_bool "cil.addNestedScopeAttr" true; + let memSafetyAnas = ["memOutOfBounds"; "memLeak"; "useAfterFree";] in + enableAnalyses memSafetyAnas) (*Detect enumerations and enable the "ana.int.enums" option*) exception EnumFound From 9efae6f8bef52e96d99052443f6a6a31a50f4dca Mon Sep 17 00:00:00 2001 From: Stanimir Bozhilov Date: Tue, 3 Oct 2023 23:50:32 +0200 Subject: [PATCH 049/140] Fix address offset calculation in `memOutOfBounds` --- src/analyses/memOutOfBounds.ml | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/analyses/memOutOfBounds.ml b/src/analyses/memOutOfBounds.ml index 9db6e58e5f..aadf433a6e 100644 --- a/src/analyses/memOutOfBounds.ml +++ b/src/analyses/memOutOfBounds.ml @@ -211,11 +211,16 @@ struct set_mem_safety_flag InvalidDeref; M.warn "Pointer %a has a top address offset. An invalid memory access may occur" d_exp ptr ); - (* Offset should be the same for all elements in the points-to set *) - (* Hence, we can just pick one element and obtain its offset *) - begin match VDQ.AD.choose a with - | Addr (_, o) -> offs_to_idx t o - | _ -> ID.top_of @@ Cilfacade.ptrdiff_ikind () + (* Get the address offsets of all points-to set elements *) + let addr_offsets = + VDQ.AD.filter (function Addr (v, o) -> true | _ -> false) a + |> VDQ.AD.to_mval + |> List.map (fun (_, o) -> offs_to_idx t o) + in + begin match addr_offsets with + | [] -> ID.bot_of @@ Cilfacade.ptrdiff_ikind () + | [x] -> x + | x::xs -> List.fold_left ID.join x xs end end | None -> From dcc3d5c3c608414092171f55fda99ebcd18d29c4 Mon Sep 17 00:00:00 2001 From: Stanimir Bozhilov Date: Tue, 3 Oct 2023 23:53:12 +0200 Subject: [PATCH 050/140] Adapt 77/10 test case to correctly account for address offsets --- tests/regression/77-mem-oob/10-oob-two-loops.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/regression/77-mem-oob/10-oob-two-loops.c b/tests/regression/77-mem-oob/10-oob-two-loops.c index 6737a212bf..5208da5a0b 100644 --- a/tests/regression/77-mem-oob/10-oob-two-loops.c +++ b/tests/regression/77-mem-oob/10-oob-two-loops.c @@ -1,4 +1,4 @@ -// PARAM: --set ana.activated[+] memOutOfBounds --enable ana.int.interval --disable warn.info +// PARAM: --set ana.activated[+] memOutOfBounds --enable ana.int.interval --disable warn.info --set sem.int.signed_overflow assume_none int main() { int *p = malloc(1048 * sizeof(int)); From a64e9c37e0b12eaa767e5f43f28b952c41ffa318 Mon Sep 17 00:00:00 2001 From: Stanimir Bozhilov Date: Tue, 3 Oct 2023 23:53:36 +0200 Subject: [PATCH 051/140] Add further test case to check address offset calculation in `memOutOfBounds` --- .../77-mem-oob/11-address-offset-oob.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 tests/regression/77-mem-oob/11-address-offset-oob.c diff --git a/tests/regression/77-mem-oob/11-address-offset-oob.c b/tests/regression/77-mem-oob/11-address-offset-oob.c new file mode 100644 index 0000000000..ba01a12873 --- /dev/null +++ b/tests/regression/77-mem-oob/11-address-offset-oob.c @@ -0,0 +1,16 @@ +// PARAM: --set ana.activated[+] memOutOfBounds --enable ana.int.interval --disable warn.info --set sem.int.signed_overflow assume_none +int main() { + int *p = malloc(2 * sizeof(int)); + int *q = p; + int x; + + if (x) { + q++; + q++; + q++; + x = *q; //WARN + } + + x = *q; //WARN + return 0; +} From 44476ce76e283c8adbdcb445c1799186cc1c3320 Mon Sep 17 00:00:00 2001 From: Stanimir Bozhilov Date: Tue, 3 Oct 2023 23:56:46 +0200 Subject: [PATCH 052/140] Set `ana.malloc.unique_address_count` for `MemorySafety` as well --- src/autoTune.ml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/autoTune.ml b/src/autoTune.ml index 10c9570d46..822195b1f6 100644 --- a/src/autoTune.ml +++ b/src/autoTune.ml @@ -241,6 +241,10 @@ let focusOnSpecification () = | MemorySafety -> (* TODO: This is a temporary solution for the memory safety category *) (print_endline "Setting \"cil.addNestedScopeAttr\" to true"; set_bool "cil.addNestedScopeAttr" true; + if (get_int "ana.malloc.unique_address_count") < 1 then ( + print_endline "Setting \"ana.malloc.unique_address_count\" to 1"; + set_int "ana.malloc.unique_address_count" 1; + ); let memSafetyAnas = ["memOutOfBounds"; "memLeak"; "useAfterFree";] in enableAnalyses memSafetyAnas) From e052544e9d225c6292ecce05a0468f3dad7b5f31 Mon Sep 17 00:00:00 2001 From: Stanimir Bozhilov Date: Wed, 4 Oct 2023 11:14:50 +0200 Subject: [PATCH 053/140] Move `cil.addNestedScopeAttr` setting to `init_options` --- src/util/cilfacade.ml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/util/cilfacade.ml b/src/util/cilfacade.ml index 8eaef280c6..6ca9023324 100644 --- a/src/util/cilfacade.ml +++ b/src/util/cilfacade.ml @@ -40,7 +40,9 @@ let is_first_field x = match x.fcomp.cfields with let init_options () = Mergecil.merge_inlines := get_bool "cil.merge.inlines"; Cil.cstd := Cil.cstd_of_string (get_string "cil.cstd"); - Cil.gnu89inline := get_bool "cil.gnu89inline" + Cil.gnu89inline := get_bool "cil.gnu89inline"; + if get_bool "cil.addNestedScopeAttr" = true then + Cabs2cil.addNestedScopeAttr := true let init () = initCIL (); @@ -51,9 +53,7 @@ let init () = (* lineDirectiveStyle := None; *) RmUnused.keepUnused := true; print_CIL_Input := true; - Cabs2cil.allowDuplication := false; - if get_bool "cil.addNestedScopeAttr" then - Cabs2cil.addNestedScopeAttr := true + Cabs2cil.allowDuplication := false let current_file = ref dummyFile From 33414703562868d35f974bc2201238733959874c Mon Sep 17 00:00:00 2001 From: Stanimir Bozhilov Date: Wed, 4 Oct 2023 11:36:10 +0200 Subject: [PATCH 054/140] Try with `cil.addNestedScopeAttr` always set to `true` --- src/util/cilfacade.ml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/util/cilfacade.ml b/src/util/cilfacade.ml index 6ca9023324..7009512adf 100644 --- a/src/util/cilfacade.ml +++ b/src/util/cilfacade.ml @@ -41,8 +41,8 @@ let init_options () = Mergecil.merge_inlines := get_bool "cil.merge.inlines"; Cil.cstd := Cil.cstd_of_string (get_string "cil.cstd"); Cil.gnu89inline := get_bool "cil.gnu89inline"; - if get_bool "cil.addNestedScopeAttr" = true then - Cabs2cil.addNestedScopeAttr := true + (* if get_bool "cil.addNestedScopeAttr" = true then *) + Cabs2cil.addNestedScopeAttr := true let init () = initCIL (); From 1211a9fe95fb881e8d53a7ab474498c31d675b7e Mon Sep 17 00:00:00 2001 From: Stanimir Bozhilov Date: Wed, 4 Oct 2023 12:25:10 +0200 Subject: [PATCH 055/140] Use rand() in 77/10 --- tests/regression/77-mem-oob/10-oob-two-loops.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tests/regression/77-mem-oob/10-oob-two-loops.c b/tests/regression/77-mem-oob/10-oob-two-loops.c index 5208da5a0b..303aac242e 100644 --- a/tests/regression/77-mem-oob/10-oob-two-loops.c +++ b/tests/regression/77-mem-oob/10-oob-two-loops.c @@ -1,15 +1,17 @@ // PARAM: --set ana.activated[+] memOutOfBounds --enable ana.int.interval --disable warn.info --set sem.int.signed_overflow assume_none +#include + int main() { int *p = malloc(1048 * sizeof(int)); for (int i = 0; i < 1048; ++i) { - p[i] = __VERIFIER_nondet_int(); //NOWARN + p[i] = rand(); //NOWARN } int *q = p; while (*q >= 0 && q < p + 1048 * sizeof(int)) { //WARN - if (__VERIFIER_nondet_int()) { + if (rand()) { q++; } else { (*q)--; //WARN From 20396754a27385fdc788557ef30704da339ae8cc Mon Sep 17 00:00:00 2001 From: Stanimir Bozhilov Date: Wed, 4 Oct 2023 12:45:14 +0200 Subject: [PATCH 056/140] Activate `cil.addNestedScopeAttr` in cilfacade only conditionally --- src/util/cilfacade.ml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/util/cilfacade.ml b/src/util/cilfacade.ml index 7009512adf..7ac3e29ee0 100644 --- a/src/util/cilfacade.ml +++ b/src/util/cilfacade.ml @@ -41,8 +41,8 @@ let init_options () = Mergecil.merge_inlines := get_bool "cil.merge.inlines"; Cil.cstd := Cil.cstd_of_string (get_string "cil.cstd"); Cil.gnu89inline := get_bool "cil.gnu89inline"; - (* if get_bool "cil.addNestedScopeAttr" = true then *) - Cabs2cil.addNestedScopeAttr := true + if get_bool "cil.addNestedScopeAttr" then + Cabs2cil.addNestedScopeAttr := true let init () = initCIL (); From fb4979b567d4664c9012d3d98a9a32ba2f0b39d9 Mon Sep 17 00:00:00 2001 From: Stanimir Bozhilov Date: Wed, 4 Oct 2023 12:46:11 +0200 Subject: [PATCH 057/140] Activate SV-COMP memory-safety-related options before CIL has completely parsed the program --- src/autoTune.ml | 21 +++++++++++++-------- src/goblint.ml | 2 ++ 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/src/autoTune.ml b/src/autoTune.ml index 822195b1f6..186d930189 100644 --- a/src/autoTune.ml +++ b/src/autoTune.ml @@ -210,15 +210,8 @@ let activateLongjmpAnalysesWhenRequired () = enableAnalyses longjmpAnalyses; ) -let focusOnSpecification () = +let focusOnMemSafetySpecification () = match Svcomp.Specification.of_option () with - | UnreachCall s -> () - | NoDataRace -> (*enable all thread analyses*) - print_endline @@ "Specification: NoDataRace -> enabling thread analyses \"" ^ (String.concat ", " notNeccessaryThreadAnalyses) ^ "\""; - enableAnalyses notNeccessaryThreadAnalyses; - | NoOverflow -> (*We focus on integer analysis*) - set_bool "ana.int.def_exc" true; - set_bool "ana.int.interval" true | ValidFree -> (* Enable the useAfterFree analysis *) let uafAna = ["useAfterFree"] in print_endline @@ "Specification: ValidFree -> enabling useAfterFree analysis \"" ^ (String.concat ", " uafAna) ^ "\""; @@ -247,6 +240,18 @@ let focusOnSpecification () = ); let memSafetyAnas = ["memOutOfBounds"; "memLeak"; "useAfterFree";] in enableAnalyses memSafetyAnas) + | _ -> () + +let focusOnSpecification () = + match Svcomp.Specification.of_option () with + | UnreachCall s -> () + | NoDataRace -> (*enable all thread analyses*) + print_endline @@ "Specification: NoDataRace -> enabling thread analyses \"" ^ (String.concat ", " notNeccessaryThreadAnalyses) ^ "\""; + enableAnalyses notNeccessaryThreadAnalyses; + | NoOverflow -> (*We focus on integer analysis*) + set_bool "ana.int.def_exc" true; + set_bool "ana.int.interval" true + | _ -> () (*Detect enumerations and enable the "ana.int.enums" option*) exception EnumFound diff --git a/src/goblint.ml b/src/goblint.ml index 4ea3a3d242..45dae3a4c6 100644 --- a/src/goblint.ml +++ b/src/goblint.ml @@ -56,6 +56,8 @@ let main () = else None in + if AutoTune.isActivated "specification" && get_string "ana.specification" <> "" then + AutoTune.focusOnMemSafetySpecification (); (* This is run independant of the autotuner being enabled or not be sound for programs with longjmp *) AutoTune.activateLongjmpAnalysesWhenRequired (); if get_bool "ana.autotune.enabled" then AutoTune.chooseConfig file; From 1eb7309b472c1392b1812fecf4adb1b2b756bb05 Mon Sep 17 00:00:00 2001 From: Stanimir Bozhilov Date: Wed, 4 Oct 2023 13:59:05 +0200 Subject: [PATCH 058/140] Fix again scoping check --- src/analyses/memOutOfBounds.ml | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/src/analyses/memOutOfBounds.ml b/src/analyses/memOutOfBounds.ml index aadf433a6e..655ed7d3f1 100644 --- a/src/analyses/memOutOfBounds.ml +++ b/src/analyses/memOutOfBounds.ml @@ -89,6 +89,10 @@ struct let pts_elems_to_sizes (addr: Queries.AD.elt) = begin match addr with | Addr (v, _) -> + if hasAttribute "goblint_cil_nested" v.vattr then ( + set_mem_safety_flag InvalidDeref; + M.warn "Var %a is potentially accessed out-of-scope. Invalid memory access may occur" CilType.Varinfo.pretty v + ); begin match v.vtype with | TArray (item_typ, _, _) -> let item_typ_size_in_bytes = size_of_type_in_bytes item_typ in @@ -233,7 +237,6 @@ struct ID.top_of @@ Cilfacade.ptrdiff_ikind () and check_lval_for_oob_access ctx ?(is_implicitly_derefed = false) lval = - check_lval_out_of_scope_access lval; (* If the lval does not contain a pointer or if it does contain a pointer, but only points to string addresses, then no need to WARN *) if (not @@ lval_contains_a_ptr lval) || ptr_only_has_str_addr ctx (Lval lval) then () else @@ -252,15 +255,6 @@ struct | _ -> check_exp_for_oob_access ctx ~is_implicitly_derefed e end - and check_lval_out_of_scope_access lval = - match lval with - | (Var v, _) -> - if hasAttribute "goblint_cil_nested" v.vattr then ( - set_mem_safety_flag InvalidDeref; - M.warn "Lvalue %a is potentially accessed out-of-scope. Invalid memory access may occur" d_lval lval - ) - | _ -> () - and check_no_binop_deref ctx lval_exp = check_unknown_addr_deref ctx lval_exp; let behavior = Undefined MemoryOutOfBoundsAccess in From a840e412a7eedcd3cd6a2c8b3166e80acb4b8f2b Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 4 Oct 2023 16:40:37 +0300 Subject: [PATCH 059/140] Extract most library extensions to std dune library --- src/dune | 19 ++++++++++--------- src/goblint_lib.ml | 17 +++-------------- src/util/std/dune | 17 +++++++++++++++++ src/util/{ => std}/gobFpath.ml | 0 src/util/{ => std}/gobGc.ml | 0 src/util/{ => std}/gobHashtbl.ml | 0 src/util/{ => std}/gobList.ml | 0 src/util/{ => std}/gobOption.ml | 0 src/util/{ => std}/gobPretty.ml | 0 src/util/{ => std}/gobRef.ml | 0 src/util/{ => std}/gobResult.ml | 0 src/util/{ => std}/gobSys.ml | 0 src/util/{ => std}/gobUnix.ml | 0 src/util/{ => std}/gobYaml.ml | 0 src/util/{ => std}/gobYojson.ml | 0 src/util/{ => std}/gobZ.ml | 0 src/util/std/goblint_std.ml | 24 ++++++++++++++++++++++++ 17 files changed, 54 insertions(+), 23 deletions(-) create mode 100644 src/util/std/dune rename src/util/{ => std}/gobFpath.ml (100%) rename src/util/{ => std}/gobGc.ml (100%) rename src/util/{ => std}/gobHashtbl.ml (100%) rename src/util/{ => std}/gobList.ml (100%) rename src/util/{ => std}/gobOption.ml (100%) rename src/util/{ => std}/gobPretty.ml (100%) rename src/util/{ => std}/gobRef.ml (100%) rename src/util/{ => std}/gobResult.ml (100%) rename src/util/{ => std}/gobSys.ml (100%) rename src/util/{ => std}/gobUnix.ml (100%) rename src/util/{ => std}/gobYaml.ml (100%) rename src/util/{ => std}/gobYojson.ml (100%) rename src/util/{ => std}/gobZ.ml (100%) create mode 100644 src/util/std/goblint_std.ml diff --git a/src/dune b/src/dune index 85944375ea..a8cda818b1 100644 --- a/src/dune +++ b/src/dune @@ -7,7 +7,7 @@ (name goblint_lib) (public_name goblint.lib) (modules :standard \ goblint mainspec privPrecCompare apronPrecCompare messagesCompare) - (libraries goblint.sites goblint.build-info goblint-cil.all-features batteries.unthreaded qcheck-core.runner sha json-data-encoding jsonrpc cpu arg-complete fpath yaml yaml.unix uuidm goblint_timing catapult goblint_backtrace fileutils + (libraries goblint.sites goblint.build-info goblint-cil.all-features batteries.unthreaded qcheck-core.runner sha json-data-encoding jsonrpc cpu arg-complete fpath yaml yaml.unix uuidm goblint_timing catapult goblint_backtrace fileutils goblint_std ; Conditionally compile based on whether apron optional dependency is installed or not. ; Alternative dependencies seem like the only way to optionally depend on optional dependencies. ; See: https://dune.readthedocs.io/en/stable/concepts.html#alternative-dependencies. @@ -56,6 +56,7 @@ (-> violationZ3.no-z3.ml) ) ) + (flags :standard -open Goblint_std) (foreign_stubs (language c) (names stubs)) (ocamlopt_flags :standard -no-float-const-prop) (preprocess @@ -77,33 +78,33 @@ (public_names goblint -) (modes byte native) ; https://dune.readthedocs.io/en/stable/dune-files.html#linking-modes (modules goblint mainspec) - (libraries goblint.lib goblint.sites.dune goblint.build-info.dune) + (libraries goblint.lib goblint.sites.dune goblint.build-info.dune goblint_std) (preprocess (pps ppx_deriving.std ppx_deriving_hash ppx_deriving_yojson)) - (flags :standard -linkall) + (flags :standard -linkall -open Goblint_std) ) (executable (name privPrecCompare) (modules privPrecCompare) - (libraries goblint.lib goblint.sites.dune goblint.build-info.dune) + (libraries goblint.lib goblint.sites.dune goblint.build-info.dune goblint_std) (preprocess (pps ppx_deriving.std ppx_deriving_hash ppx_deriving_yojson)) - (flags :standard -linkall) + (flags :standard -linkall -open Goblint_std) ) (executable (name apronPrecCompare) (modules apronPrecCompare) - (libraries goblint.lib goblint.sites.dune goblint.build-info.dune) + (libraries goblint.lib goblint.sites.dune goblint.build-info.dune goblint_std) (preprocess (pps ppx_deriving.std ppx_deriving_hash ppx_deriving_yojson)) - (flags :standard -linkall) + (flags :standard -linkall -open Goblint_std) ) (executable (name messagesCompare) (modules messagesCompare) - (libraries goblint.lib goblint.sites.dune goblint.build-info.dune) + (libraries goblint.lib goblint.sites.dune goblint.build-info.dune goblint_std) (preprocess (pps ppx_deriving.std ppx_deriving_hash ppx_deriving_yojson)) - (flags :standard -linkall) + (flags :standard -linkall -open Goblint_std) ) (rule diff --git a/src/goblint_lib.ml b/src/goblint_lib.ml index 6e700485dd..816a69faff 100644 --- a/src/goblint_lib.ml +++ b/src/goblint_lib.ml @@ -469,29 +469,18 @@ module ConfigVersion = ConfigVersion (** {1 Library extensions} - OCaml library extensions which are completely independent of Goblint. *) + OCaml library extensions which are completely independent of Goblint. + + See {!Goblint_std}. *) (** {2 Standard library} OCaml standard library extensions which are not provided by {!Batteries}. *) module GobFormat = GobFormat -module GobGc = GobGc -module GobHashtbl = GobHashtbl -module GobList = GobList -module GobRef = GobRef -module GobResult = GobResult -module GobOption = GobOption -module GobSys = GobSys -module GobUnix = GobUnix (** {2 Other libraries} External library extensions. *) -module GobFpath = GobFpath -module GobPretty = GobPretty -module GobYaml = GobYaml -module GobYojson = GobYojson -module GobZ = GobZ module MyCheck = MyCheck diff --git a/src/util/std/dune b/src/util/std/dune new file mode 100644 index 0000000000..c85710a8d6 --- /dev/null +++ b/src/util/std/dune @@ -0,0 +1,17 @@ +(include_subdirs no) + +(library + (name goblint_std) + (public_name goblint.std) + (libraries + batteries + zarith + goblint-cil + fpath + yojson + yaml) + (preprocess + (pps + ppx_deriving.std + ppx_deriving_hash + ppx_deriving_yojson))) diff --git a/src/util/gobFpath.ml b/src/util/std/gobFpath.ml similarity index 100% rename from src/util/gobFpath.ml rename to src/util/std/gobFpath.ml diff --git a/src/util/gobGc.ml b/src/util/std/gobGc.ml similarity index 100% rename from src/util/gobGc.ml rename to src/util/std/gobGc.ml diff --git a/src/util/gobHashtbl.ml b/src/util/std/gobHashtbl.ml similarity index 100% rename from src/util/gobHashtbl.ml rename to src/util/std/gobHashtbl.ml diff --git a/src/util/gobList.ml b/src/util/std/gobList.ml similarity index 100% rename from src/util/gobList.ml rename to src/util/std/gobList.ml diff --git a/src/util/gobOption.ml b/src/util/std/gobOption.ml similarity index 100% rename from src/util/gobOption.ml rename to src/util/std/gobOption.ml diff --git a/src/util/gobPretty.ml b/src/util/std/gobPretty.ml similarity index 100% rename from src/util/gobPretty.ml rename to src/util/std/gobPretty.ml diff --git a/src/util/gobRef.ml b/src/util/std/gobRef.ml similarity index 100% rename from src/util/gobRef.ml rename to src/util/std/gobRef.ml diff --git a/src/util/gobResult.ml b/src/util/std/gobResult.ml similarity index 100% rename from src/util/gobResult.ml rename to src/util/std/gobResult.ml diff --git a/src/util/gobSys.ml b/src/util/std/gobSys.ml similarity index 100% rename from src/util/gobSys.ml rename to src/util/std/gobSys.ml diff --git a/src/util/gobUnix.ml b/src/util/std/gobUnix.ml similarity index 100% rename from src/util/gobUnix.ml rename to src/util/std/gobUnix.ml diff --git a/src/util/gobYaml.ml b/src/util/std/gobYaml.ml similarity index 100% rename from src/util/gobYaml.ml rename to src/util/std/gobYaml.ml diff --git a/src/util/gobYojson.ml b/src/util/std/gobYojson.ml similarity index 100% rename from src/util/gobYojson.ml rename to src/util/std/gobYojson.ml diff --git a/src/util/gobZ.ml b/src/util/std/gobZ.ml similarity index 100% rename from src/util/gobZ.ml rename to src/util/std/gobZ.ml diff --git a/src/util/std/goblint_std.ml b/src/util/std/goblint_std.ml new file mode 100644 index 0000000000..e716d1df5b --- /dev/null +++ b/src/util/std/goblint_std.ml @@ -0,0 +1,24 @@ +(** OCaml library extensions which are completely independent of Goblint. *) + +(** {1 Standard library} + + OCaml standard library extensions which are not provided by {!Batteries}. *) + +module GobGc = GobGc +module GobHashtbl = GobHashtbl +module GobList = GobList +module GobRef = GobRef +module GobResult = GobResult +module GobOption = GobOption +module GobSys = GobSys +module GobUnix = GobUnix + +(** {1 Other libraries} + + External library extensions. *) + +module GobFpath = GobFpath +module GobPretty = GobPretty +module GobYaml = GobYaml +module GobYojson = GobYojson +module GobZ = GobZ From 4a4b6abc6edd18d1487084131a4f3bc038fe526f Mon Sep 17 00:00:00 2001 From: Stanimir Bozhilov Date: Wed, 4 Oct 2023 19:48:48 +0200 Subject: [PATCH 060/140] Fix conditional enabling of `cil.addNestedScopeAttr` --- src/goblint.ml | 2 -- src/maingoblint.ml | 2 ++ 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/goblint.ml b/src/goblint.ml index 45dae3a4c6..4ea3a3d242 100644 --- a/src/goblint.ml +++ b/src/goblint.ml @@ -56,8 +56,6 @@ let main () = else None in - if AutoTune.isActivated "specification" && get_string "ana.specification" <> "" then - AutoTune.focusOnMemSafetySpecification (); (* This is run independant of the autotuner being enabled or not be sound for programs with longjmp *) AutoTune.activateLongjmpAnalysesWhenRequired (); if get_bool "ana.autotune.enabled" then AutoTune.chooseConfig file; diff --git a/src/maingoblint.ml b/src/maingoblint.ml index 155faa0e76..0f061a3507 100644 --- a/src/maingoblint.ml +++ b/src/maingoblint.ml @@ -185,6 +185,8 @@ let handle_options () = check_arguments (); AfterConfig.run (); Sys.set_signal (GobSys.signal_of_string (get_string "dbg.solver-signal")) Signal_ignore; (* Ignore solver-signal before solving (e.g. MyCFG), otherwise exceptions self-signal the default, which crashes instead of printing backtrace. *) + if AutoTune.isActivated "specification" && get_string "ana.specification" <> "" then + AutoTune.focusOnMemSafetySpecification (); Cilfacade.init_options (); handle_flags () From 395c30db266591bc2e20b663274628278bb3b6f0 Mon Sep 17 00:00:00 2001 From: Stanimir Bozhilov Date: Wed, 4 Oct 2023 20:39:15 +0200 Subject: [PATCH 061/140] Warn for invalid deallocation when encountering invalid addresses --- src/analyses/base.ml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/analyses/base.ml b/src/analyses/base.ml index 81bd29f8d0..a9457ca41b 100644 --- a/src/analyses/base.ml +++ b/src/analyses/base.ml @@ -2039,7 +2039,9 @@ struct AnalysisStateUtil.set_mem_safety_flag InvalidFree; M.warn ~category:(Behavior (Undefined InvalidMemoryDeallocation)) ~tags:[CWE 761] "Free of memory not at start of buffer in function %s for pointer %a" special_fn.vname d_exp ptr ) - | _ -> M.warn ~category:MessageCategory.Analyzer "Pointer %a in function %s doesn't evaluate to a valid address." d_exp ptr special_fn.vname + | _ -> + AnalysisStateUtil.set_mem_safety_flag InvalidFree; + M.warn ~category:(Behavior (Undefined InvalidMemoryDeallocation)) ~tags:[CWE 590] "Pointer %a in function %s doesn't evaluate to a valid address. Invalid memory deallocation may occur" d_exp ptr special_fn.vname let special ctx (lv:lval option) (f: varinfo) (args: exp list) = From 055d9cc01b2fa8332c00e9011183d18cd2bf2fc6 Mon Sep 17 00:00:00 2001 From: Stanimir Bozhilov Date: Wed, 4 Oct 2023 20:39:39 +0200 Subject: [PATCH 062/140] Add invalid address test case for invalid deallocation --- .../10-invalid-dealloc-union.c | 42 +++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 tests/regression/75-invalid_dealloc/10-invalid-dealloc-union.c diff --git a/tests/regression/75-invalid_dealloc/10-invalid-dealloc-union.c b/tests/regression/75-invalid_dealloc/10-invalid-dealloc-union.c new file mode 100644 index 0000000000..be1eaa056d --- /dev/null +++ b/tests/regression/75-invalid_dealloc/10-invalid-dealloc-union.c @@ -0,0 +1,42 @@ +extern void abort(void); +#include + +extern int __VERIFIER_nondet_int(void); + +int main() +{ + union { + void *p0; + + struct { + char c[2]; + int p1; + int p2; + } str; + + } data; + + // alloc 37B on heap + data.p0 = malloc(37U); + + // avoid introducing a memleak + void *ptr = data.p0; + + // this should be fine + if(__VERIFIER_nondet_int()) { + data.str.p2 = 20; + } else { + data.str.p2 = 30; + } + + if(25 > data.str.p2) { + // avoids memleak + data.str.c[1] = sizeof data.str.p1; + } + + // invalid free() + free(data.p0);//WARN + + free(ptr);//NOWARN + return 0; +} From 2c883eb32cc67f17a48bb4ff7aca73f5811a056b Mon Sep 17 00:00:00 2001 From: Stanimir Bozhilov Date: Wed, 4 Oct 2023 21:58:30 +0200 Subject: [PATCH 063/140] Warn if lval contains an address with a non-local var --- src/analyses/base.ml | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/analyses/base.ml b/src/analyses/base.ml index a9457ca41b..a323e5f270 100644 --- a/src/analyses/base.ml +++ b/src/analyses/base.ml @@ -1051,7 +1051,18 @@ struct else if AD.may_be_null adr then ( AnalysisStateUtil.set_mem_safety_flag InvalidDeref; M.warn ~category:M.Category.Behavior.Undefined.nullpointer_dereference ~tags:[CWE 476] "May dereference NULL pointer" - ) + ); + (* Warn if any of the addresses contains a non-local variable *) + AD.iter (function + | AD.Addr.Addr (v,o) -> + if not @@ CPA.mem v st.cpa then ( + (* TODO: Not the smartest move to set the global flag within an iter *) + (* TODO: We can resort to using AD.exists instead *) + AnalysisStateUtil.set_mem_safety_flag InvalidDeref; + M.warn "lval %a points to non-local variable %a. Invalid pointer dereference may occur" d_lval lval CilType.Varinfo.pretty v + ) + | _ -> () + ) adr ); AD.map (add_offset_varinfo (convert_offset a gs st ofs)) adr | _ -> From 5cb10f61925e55932475e859569d496a630fee6a Mon Sep 17 00:00:00 2001 From: Stanimir Bozhilov Date: Wed, 4 Oct 2023 22:09:51 +0200 Subject: [PATCH 064/140] Don't warn for non-local vars in address set if they're globals --- src/analyses/base.ml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/analyses/base.ml b/src/analyses/base.ml index a323e5f270..a5b60e8cca 100644 --- a/src/analyses/base.ml +++ b/src/analyses/base.ml @@ -1055,7 +1055,7 @@ struct (* Warn if any of the addresses contains a non-local variable *) AD.iter (function | AD.Addr.Addr (v,o) -> - if not @@ CPA.mem v st.cpa then ( + if not (CPA.mem v st.cpa) && not (is_global a v) then ( (* TODO: Not the smartest move to set the global flag within an iter *) (* TODO: We can resort to using AD.exists instead *) AnalysisStateUtil.set_mem_safety_flag InvalidDeref; From ea4410d8d0939d93f5effa56fd51c9549c717641 Mon Sep 17 00:00:00 2001 From: Stanimir Bozhilov Date: Wed, 4 Oct 2023 22:10:11 +0200 Subject: [PATCH 065/140] Add test cases for invalid deref due to scoping --- .../01-scopes-no-static.c | 22 ++++++++ .../02-scopes-global-var.c | 29 +++++++++++ .../03-scopes-static.c | 52 +++++++++++++++++++ 3 files changed, 103 insertions(+) create mode 100644 tests/regression/78-invalid-deref-scopes/01-scopes-no-static.c create mode 100644 tests/regression/78-invalid-deref-scopes/02-scopes-global-var.c create mode 100644 tests/regression/78-invalid-deref-scopes/03-scopes-static.c diff --git a/tests/regression/78-invalid-deref-scopes/01-scopes-no-static.c b/tests/regression/78-invalid-deref-scopes/01-scopes-no-static.c new file mode 100644 index 0000000000..e0c4b47b73 --- /dev/null +++ b/tests/regression/78-invalid-deref-scopes/01-scopes-no-static.c @@ -0,0 +1,22 @@ +// PARAM: --set ana.activated[+] memOutOfBounds +// TODO: I haven't checked why, but we need memOutOfBounds for this case +extern int printf ( const char * format, ... ); + +int *foo2(void) +{ + int arr[1024]; + arr[194] = 13; + return arr + 1; +} + +int *foo(void) +{ + int arr[123]; + return foo2(); +} + +int main(void) { + int *a = foo(); + printf("%d\n", *a);//WARN + return 0; +} diff --git a/tests/regression/78-invalid-deref-scopes/02-scopes-global-var.c b/tests/regression/78-invalid-deref-scopes/02-scopes-global-var.c new file mode 100644 index 0000000000..9491e1c574 --- /dev/null +++ b/tests/regression/78-invalid-deref-scopes/02-scopes-global-var.c @@ -0,0 +1,29 @@ +int array[10]; + +// function returns array of numbers +int* getNumbers(void) { + for (int i = 0; i < 10; ++i) { + array[i] = i;//NOWARN + } + + return array; +} + +int* getNumbers2(void) { + int* numbers = getNumbers(); + // numbers2 is local + int numbers2[10]; + + for (int i = 0; i < 10; ++i) { + numbers2[i] = numbers[i];//NOWARN + } + + return numbers2; +} + +int main(void) { + int *numbers = getNumbers2(); + numbers[0] = 100;//WARN + + return 0; +} diff --git a/tests/regression/78-invalid-deref-scopes/03-scopes-static.c b/tests/regression/78-invalid-deref-scopes/03-scopes-static.c new file mode 100644 index 0000000000..c13b665c84 --- /dev/null +++ b/tests/regression/78-invalid-deref-scopes/03-scopes-static.c @@ -0,0 +1,52 @@ +extern int printf (const char* format, ...); + +// function returns array of numbers +int* getNumbers() { + + static int array[10]; + + for (int i = 0; i < 10; ++i) { + array[i] = i;//NOWARN + } + + return array; +} + +int* getNumbers2() { + int* numbers = getNumbers(); + static int numbers2[10]; + for (int i = 0; i < 10; ++i) { + numbers2[i] = numbers[i];//NOWARN + } + return numbers2; +} + +int* getNumbers3() { + int* numbers = getNumbers2(); + int numbers3[10]; + for (int i = 0; i < 10; ++i) { + numbers3[i] = numbers[i];//NOWARN + } + + return numbers3; +} + +int* getNumbers4() { + int* numbers = getNumbers3(); + static int numbers4[10]; + for (int i = 0; i < 10; ++i) { + numbers4[i] = numbers[i];//WARN + } + return numbers4; +} + +int main (void) { + + int *numbers = getNumbers4(); + + for (int i = 0; i < 10; i++ ) { + printf( "%d\n", *(numbers + i));//NOWARN + } + + return 0; +} From 6745d799de882a056df9dd0c695668592a5f31eb Mon Sep 17 00:00:00 2001 From: Stanimir Bozhilov Date: Wed, 4 Oct 2023 22:49:37 +0200 Subject: [PATCH 066/140] Slightly refactor `check_count` and check for `src`'s size in `memcpy` --- src/analyses/memOutOfBounds.ml | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/analyses/memOutOfBounds.ml b/src/analyses/memOutOfBounds.ml index 655ed7d3f1..8a2ca12467 100644 --- a/src/analyses/memOutOfBounds.ml +++ b/src/analyses/memOutOfBounds.ml @@ -372,22 +372,22 @@ struct | _ -> () (* For memset() and memcpy() *) - let check_count ctx fun_name dest n = + let check_count ctx fun_name ptr n = let (behavior:MessageCategory.behavior) = Undefined MemoryOutOfBoundsAccess in let cwe_number = 823 in - let dest_size = get_size_of_ptr_target ctx dest in + let ptr_size = get_size_of_ptr_target ctx ptr in let eval_n = ctx.ask (Queries.EvalInt n) in - let addr_offs = get_addr_offs ctx dest in - match dest_size, eval_n with + let addr_offs = get_addr_offs ctx ptr in + match ptr_size, eval_n with | `Top, _ -> set_mem_safety_flag InvalidDeref; - M.warn ~category:(Behavior behavior) ~tags:[CWE cwe_number] "Size of dest %a in function %s is unknown. Memory out-of-bounds access might occur" d_exp dest fun_name + M.warn ~category:(Behavior behavior) ~tags:[CWE cwe_number] "Size of dest %a in function %s is unknown. Memory out-of-bounds access might occur" d_exp ptr fun_name | _, `Top -> set_mem_safety_flag InvalidDeref; M.warn ~category:(Behavior behavior) ~tags:[CWE cwe_number] "Count parameter, passed to function %s is unknown. Memory out-of-bounds access might occur" fun_name | `Bot, _ -> set_mem_safety_flag InvalidDeref; - M.warn ~category:(Behavior behavior) ~tags:[CWE cwe_number] "Size of dest %a in function %s is bottom. Memory out-of-bounds access might occur" d_exp dest fun_name + M.warn ~category:(Behavior behavior) ~tags:[CWE cwe_number] "Size of dest %a in function %s is bottom. Memory out-of-bounds access might occur" d_exp ptr fun_name | _, `Bot -> set_mem_safety_flag InvalidDeref; M.warn ~category:(Behavior behavior) ~tags:[CWE cwe_number] "Count parameter, passed to function %s is bottom" fun_name @@ -399,7 +399,7 @@ struct begin match ID.to_bool dest_size_lt_count with | Some true -> set_mem_safety_flag InvalidDeref; - M.warn ~category:(Behavior behavior) ~tags:[CWE cwe_number] "Size of dest in function %s is %a (in bytes) with an address offset of %a (in bytes). Count is %a (in bytes). Memory out-of-bounds access must occur" fun_name ID.pretty casted_ds ID.pretty casted_ao ID.pretty casted_en + M.warn ~category:(Behavior behavior) ~tags:[CWE cwe_number] "Size of %a in function %s is %a (in bytes) with an address offset of %a (in bytes). Count is %a (in bytes). Memory out-of-bounds access must occur" d_exp ptr fun_name ID.pretty casted_ds ID.pretty casted_ao ID.pretty casted_en | Some false -> () | None -> set_mem_safety_flag InvalidDeref; @@ -436,7 +436,9 @@ struct (* Check calls to memset and memcpy for out-of-bounds-accesses *) match desc.special arglist with | Memset { dest; ch; count; } -> check_count ctx f.vname dest count; - | Memcpy { dest; src; n = count; } -> check_count ctx f.vname dest count; + | Memcpy { dest; src; n = count; } -> + check_count ctx f.vname src count; + check_count ctx f.vname dest count; | _ -> (); ctx.local From 136bec0232107c61a42a3ed369a03aee90fbf2b8 Mon Sep 17 00:00:00 2001 From: Stanimir Bozhilov Date: Wed, 4 Oct 2023 22:50:41 +0200 Subject: [PATCH 067/140] Add test case with wrong src size for memcpy --- .../regression/77-mem-oob/12-memcpy-oob-src.c | 43 +++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 tests/regression/77-mem-oob/12-memcpy-oob-src.c diff --git a/tests/regression/77-mem-oob/12-memcpy-oob-src.c b/tests/regression/77-mem-oob/12-memcpy-oob-src.c new file mode 100644 index 0000000000..0f3a609fbe --- /dev/null +++ b/tests/regression/77-mem-oob/12-memcpy-oob-src.c @@ -0,0 +1,43 @@ +// PARAM: --set ana.activated[+] memOutOfBounds --enable ana.int.interval --disable warn.info +// TODO: The "--disable warn.info" part is a temporary fix and needs to be removed once the MacOS CI job is fixed +#include +#include + +struct A { + unsigned char a; + unsigned char b:2; + unsigned char c:2; + unsigned char d:5; + unsigned char e; +} __attribute__((packed)); + +struct A d; +int main(void) +{ + struct A *p; + p = malloc(5); + d.a = 1; + d.b = 2; + d.c = 3; + d.d = 4; + d.e = 5; + // It's an OOB error, because sizeof(d) == 4 + memcpy(p, &d, 5); //WARN + if (p->a != 1) { + free(p); + } + if (p->b != 2) { + free(p); + } + if (p->c != 3) { + free(p); + } + if (p->d != 4) { + free(p); + } + if (p->e != 5) { + free(p); + } + free(p); +} + From 3a2fe3f09278fc80fe8e6b68c3697f6996bf7030 Mon Sep 17 00:00:00 2001 From: Stanimir Bozhilov Date: Wed, 4 Oct 2023 22:53:50 +0200 Subject: [PATCH 068/140] Correct test 77/07 to warn for src OOB access in memcpy as well --- tests/regression/77-mem-oob/07-memcpy-oob.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/regression/77-mem-oob/07-memcpy-oob.c b/tests/regression/77-mem-oob/07-memcpy-oob.c index 012f92996e..5605404a87 100644 --- a/tests/regression/77-mem-oob/07-memcpy-oob.c +++ b/tests/regression/77-mem-oob/07-memcpy-oob.c @@ -31,13 +31,13 @@ int main(int argc, char const *argv[]) { memcpy(a, b, 40); //WARN memcpy(a, b, sizeof(a)); //WARN - memcpy(b, a, 60); //NOWARN + memcpy(b, a, 60); //WARN b += 1; memcpy(b, a, 60); //WARN s *s_ptr = malloc(sizeof(s)); - memcpy(s_ptr, a, sizeof(s)); //NOWARN + memcpy(s_ptr, a, sizeof(s)); //WARN memcpy(s_ptr->a, 0, sizeof(s)); //WARN memcpy(s_ptr->b, 0, sizeof(s)); //WARN From 0776dbe5423c38aa74acfbdc1cdd88c148e2051d Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 5 Oct 2023 12:02:14 +0300 Subject: [PATCH 069/140] Add __builtin_clzll to library functions --- src/analyses/libraryFunctions.ml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/analyses/libraryFunctions.ml b/src/analyses/libraryFunctions.ml index 9ee9dc8c9d..7695844dd0 100644 --- a/src/analyses/libraryFunctions.ml +++ b/src/analyses/libraryFunctions.ml @@ -374,6 +374,8 @@ let gcc_descs_list: (string * LibraryDesc.t) list = LibraryDsl.[ ("__builtin_ctzl", unknown [drop "x" []]); ("__builtin_ctzll", unknown [drop "x" []]); ("__builtin_clz", unknown [drop "x" []]); + ("__builtin_clzl", unknown [drop "x" []]); + ("__builtin_clzll", unknown [drop "x" []]); ("__builtin_object_size", unknown [drop "ptr" [r]; drop' []]); ("__builtin_prefetch", unknown (drop "addr" [] :: VarArgs (drop' []))); ("__builtin_expect", special [__ "exp" []; drop' []] @@ fun exp -> Identity exp); (* Identity, because just compiler optimization annotation. *) From 7b76751a6cc2100f7c303c481fe28c0b7a4737a4 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 5 Oct 2023 12:37:54 +0300 Subject: [PATCH 070/140] Move config modules to build_info dune library --- src/build-info/.gitignore | 1 + ...blint_build_info.ml => dune_build_info.ml} | 0 ...blint_build_info.ml => dune_build_info.ml} | 0 src/build-info/dune | 20 ++++++++++- ...int_build_info.mli => dune_build_info.mli} | 0 src/build-info/goblint_build_info.ml | 34 +++++++++++++++++++ src/dune | 16 --------- src/framework/control.ml | 2 +- src/goblint_lib.ml | 15 -------- src/maingoblint.ml | 6 ++-- src/util/sarif.ml | 2 +- src/util/tracing.ml | 2 +- src/version.ml | 16 --------- src/witness/witness.ml | 2 +- src/witness/yamlWitness.ml | 2 +- 15 files changed, 62 insertions(+), 56 deletions(-) create mode 100644 src/build-info/.gitignore rename src/build-info/build_info_dune/{goblint_build_info.ml => dune_build_info.ml} (100%) rename src/build-info/build_info_js/{goblint_build_info.ml => dune_build_info.ml} (100%) rename src/build-info/{goblint_build_info.mli => dune_build_info.mli} (100%) create mode 100644 src/build-info/goblint_build_info.ml delete mode 100644 src/version.ml diff --git a/src/build-info/.gitignore b/src/build-info/.gitignore new file mode 100644 index 0000000000..8afff91d71 --- /dev/null +++ b/src/build-info/.gitignore @@ -0,0 +1 @@ +config*.ml diff --git a/src/build-info/build_info_dune/goblint_build_info.ml b/src/build-info/build_info_dune/dune_build_info.ml similarity index 100% rename from src/build-info/build_info_dune/goblint_build_info.ml rename to src/build-info/build_info_dune/dune_build_info.ml diff --git a/src/build-info/build_info_js/goblint_build_info.ml b/src/build-info/build_info_js/dune_build_info.ml similarity index 100% rename from src/build-info/build_info_js/goblint_build_info.ml rename to src/build-info/build_info_js/dune_build_info.ml diff --git a/src/build-info/dune b/src/build-info/dune index 89ae841778..c1de250263 100644 --- a/src/build-info/dune +++ b/src/build-info/dune @@ -8,4 +8,22 @@ (library (name goblint_build_info) (public_name goblint.build-info) - (virtual_modules goblint_build_info)) + (libraries batteries.unthreaded) + (virtual_modules dune_build_info)) + +(rule + (target configVersion.ml) + (mode (promote (until-clean) (only configVersion.ml))) ; replace existing file in source tree, even if releasing (only overrides) + (deps (universe)) ; do not cache, always regenerate + (action (pipe-stdout (bash "git describe --all --long --dirty || echo \"n/a\"") (with-stdout-to %{target} (bash "xargs printf '(* Automatically regenerated, changes do not persist! *)\nlet version = \"%s\"'"))))) + +(rule + (target configProfile.ml) + (mode (promote (until-clean) (only configProfile.ml))) ; replace existing file in source tree, even if releasing (only overrides) + (action (write-file %{target} "(* Automatically regenerated, changes do not persist! *)\nlet profile = \"%{profile}\""))) + +(rule + (target configOcaml.ml) + (mode (promote (until-clean) (only configOcaml.ml))) ; replace existing file in source tree, even if releasing (only overrides) + (action (write-file %{target} "(* Automatically regenerated, changes do not persist! *)\nlet flambda = \"%{ocaml-config:flambda}\""))) + diff --git a/src/build-info/goblint_build_info.mli b/src/build-info/dune_build_info.mli similarity index 100% rename from src/build-info/goblint_build_info.mli rename to src/build-info/dune_build_info.mli diff --git a/src/build-info/goblint_build_info.ml b/src/build-info/goblint_build_info.ml new file mode 100644 index 0000000000..cf5165d51c --- /dev/null +++ b/src/build-info/goblint_build_info.ml @@ -0,0 +1,34 @@ +(** Goblint build info. *) + +(** OCaml compiler flambda status. *) +let ocaml_flambda = ConfigOcaml.flambda + +(** Dune profile. *) +let dune_profile = ConfigProfile.profile + +(** Goblint version from git. *) +let git_version = ConfigVersion.version + +(** Goblint version from release archive. *) +let release_version = "%%VERSION_NUM%%" + +(** Goblint git commit from release archive. *) +let release_commit = "%%VCS_COMMIT_ID%%" + +(** Goblint version. *) +let version = + let commit = ConfigVersion.version in + if BatString.starts_with release_version "%" then + commit + else ( + let commit = + if commit = "n/a" then (* released archive has no .git *) + release_commit + else + commit + in + Format.sprintf "%s (%s)" release_version commit + ) + +(** Statically linked libraries with versions. *) +let statically_linked_libraries = Dune_build_info.statically_linked_libraries diff --git a/src/dune b/src/dune index a8cda818b1..5fdf58a5b2 100644 --- a/src/dune +++ b/src/dune @@ -107,22 +107,6 @@ (flags :standard -linkall -open Goblint_std) ) -(rule - (target configVersion.ml) - (mode (promote (until-clean) (only configVersion.ml))) ; replace existing file in source tree, even if releasing (only overrides) - (deps (universe)) ; do not cache, always regenerate - (action (pipe-stdout (bash "git describe --all --long --dirty || echo \"n/a\"") (with-stdout-to %{target} (bash "xargs printf '(* Automatically regenerated, changes do not persist! *)\nlet version = \"%s\"'"))))) - -(rule - (target configProfile.ml) - (mode (promote (until-clean) (only configProfile.ml))) ; replace existing file in source tree, even if releasing (only overrides) - (action (write-file %{target} "(* Automatically regenerated, changes do not persist! *)\nlet profile = \"%{profile}\""))) - -(rule - (target configOcaml.ml) - (mode (promote (until-clean) (only configOcaml.ml))) ; replace existing file in source tree, even if releasing (only overrides) - (action (write-file %{target} "(* Automatically regenerated, changes do not persist! *)\nlet flambda = \"%{ocaml-config:flambda}\""))) - (rule (alias runtest) (deps ../goblint ../scripts/update_suite.rb ../Makefile ../make.sh (source_tree ../tests/regression) (source_tree ../includes) (source_tree ../linux-headers)) diff --git a/src/framework/control.ml b/src/framework/control.ml index 5cefc1a7de..9baa2dd1ca 100644 --- a/src/framework/control.ml +++ b/src/framework/control.ml @@ -529,7 +529,7 @@ struct GobConfig.write_file config; let module Meta = struct type t = { command : string; version: string; timestamp : float; localtime : string } [@@deriving to_yojson] - let json = to_yojson { command = GobSys.command_line; version = Version.goblint; timestamp = Unix.time (); localtime = GobUnix.localtime () } + let json = to_yojson { command = GobSys.command_line; version = Goblint_build_info.version; timestamp = Unix.time (); localtime = GobUnix.localtime () } end in (* Yojson.Safe.to_file meta Meta.json; *) diff --git a/src/goblint_lib.ml b/src/goblint_lib.ml index 816a69faff..e009ecf86b 100644 --- a/src/goblint_lib.ml +++ b/src/goblint_lib.ml @@ -452,21 +452,6 @@ module PrivPrecCompareUtil = PrivPrecCompareUtil module RelationPrecCompareUtil = RelationPrecCompareUtil module ApronPrecCompareUtil = ApronPrecCompareUtil -(** {2 Build info} *) - -(** OCaml compiler info. *) -module ConfigOcaml = ConfigOcaml - -(** Dune profile info. *) -module ConfigProfile = ConfigProfile - -(** Goblint version info. *) -module Version = Version - -(** Goblint git version info. *) -module ConfigVersion = ConfigVersion - - (** {1 Library extensions} OCaml library extensions which are completely independent of Goblint. diff --git a/src/maingoblint.ml b/src/maingoblint.ml index 7808cbcd3f..98363233a2 100644 --- a/src/maingoblint.ml +++ b/src/maingoblint.ml @@ -9,11 +9,11 @@ let writeconffile = ref None (** Print version and bail. *) let print_version ch = - printf "Goblint version: %s\n" Version.goblint; + printf "Goblint version: %s\n" Goblint_build_info.version; printf "Cil version: %s\n" Cil.cilVersion; - printf "Dune profile: %s\n" ConfigProfile.profile; + printf "Dune profile: %s\n" Goblint_build_info.dune_profile; printf "OCaml version: %s\n" Sys.ocaml_version; - printf "OCaml flambda: %s\n" ConfigOcaml.flambda; + printf "OCaml flambda: %s\n" Goblint_build_info.ocaml_flambda; if get_bool "dbg.verbose" then ( printf "Library versions:\n"; List.iter (fun (name, version) -> diff --git a/src/util/sarif.ml b/src/util/sarif.ml index 4374da46d7..7620384cc4 100644 --- a/src/util/sarif.ml +++ b/src/util/sarif.ml @@ -26,7 +26,7 @@ let goblintTool: Tool.t = { fullName = "Goblint static analyser"; informationUri = "https://goblint.in.tum.de/home"; organization = "TUM - i2 and UTartu - SWS"; - version = Version.goblint; + version = Goblint_build_info.version; rules = List.map transformToReportingDescriptor (List.map (fun rule -> rule.name) rules) }; } diff --git a/src/util/tracing.ml b/src/util/tracing.ml index f9dff2c2cf..ad8892c396 100644 --- a/src/util/tracing.ml +++ b/src/util/tracing.ml @@ -10,7 +10,7 @@ open Pretty module Strs = Set.Make (String) -let tracing = ConfigProfile.profile = "trace" +let tracing = Goblint_build_info.dune_profile = "trace" let current_loc = ref locUnknown let next_loc = ref locUnknown diff --git a/src/version.ml b/src/version.ml deleted file mode 100644 index cbe2874608..0000000000 --- a/src/version.ml +++ /dev/null @@ -1,16 +0,0 @@ -let release = "%%VERSION_NUM%%" -let release_commit = "%%VCS_COMMIT_ID%%" - -let goblint = - let commit = ConfigVersion.version in - if BatString.starts_with release "%" then - commit - else ( - let commit = - if commit = "n/a" then (* released archive has no .git *) - release_commit - else - commit - in - Format.sprintf "%s (%s)" release commit - ) diff --git a/src/witness/witness.ml b/src/witness/witness.ml index 0e237716fd..fb1604f03e 100644 --- a/src/witness/witness.ml +++ b/src/witness/witness.ml @@ -118,7 +118,7 @@ let write_file filename (module Task:Task) (module TaskResult:WitnessTaskResult) | Result.Unknown -> "unknown_witness" ); GML.write_metadata g "sourcecodelang" "C"; - GML.write_metadata g "producer" (Printf.sprintf "Goblint (%s)" Version.goblint); + GML.write_metadata g "producer" (Printf.sprintf "Goblint (%s)" Goblint_build_info.version); GML.write_metadata g "specification" (Svcomp.Specification.to_string Task.specification); let programfile = (Node.location (N.cfgnode main_entry)).file in GML.write_metadata g "programfile" programfile; diff --git a/src/witness/yamlWitness.ml b/src/witness/yamlWitness.ml index c7106a57b5..72ff21f6bd 100644 --- a/src/witness/yamlWitness.ml +++ b/src/witness/yamlWitness.ml @@ -17,7 +17,7 @@ struct (* let yaml_conf: Yaml.value = Json_repr.convert (module Json_repr.Yojson) (module Json_repr.Ezjsonm) (!GobConfig.json_conf) in *) let producer: Producer.t = { name = "Goblint"; - version = Version.goblint; + version = Goblint_build_info.version; command_line = Some GobSys.command_line; } From 9b728d352169f0eea1e4a21609233413f2ae1c79 Mon Sep 17 00:00:00 2001 From: Stanimir Bozhilov Date: Thu, 5 Oct 2023 13:59:19 +0200 Subject: [PATCH 071/140] Set `dest` in `memcpy` to top if `n` doesn't match its size --- src/analyses/base.ml | 85 +++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 81 insertions(+), 4 deletions(-) diff --git a/src/analyses/base.ml b/src/analyses/base.ml index a5b60e8cca..2d779b8d85 100644 --- a/src/analyses/base.ml +++ b/src/analyses/base.ml @@ -2054,6 +2054,64 @@ struct AnalysisStateUtil.set_mem_safety_flag InvalidFree; M.warn ~category:(Behavior (Undefined InvalidMemoryDeallocation)) ~tags:[CWE 590] "Pointer %a in function %s doesn't evaluate to a valid address. Invalid memory deallocation may occur" d_exp ptr special_fn.vname + let points_to_heap_only ctx ptr = + match ctx.ask (Queries.MayPointTo ptr) with + | a when not (Queries.AD.is_top a)-> + Queries.AD.for_all (function + | Addr (v, o) -> ctx.ask (Queries.IsHeapVar v) + | _ -> false + ) a + | _ -> false + + let get_size_of_ptr_target ctx ptr = + let intdom_of_int x = + ID.of_int (Cilfacade.ptrdiff_ikind ()) (Z.of_int x) + in + let size_of_type_in_bytes typ = + let typ_size_in_bytes = (bitsSizeOf typ) / 8 in + intdom_of_int typ_size_in_bytes + in + if points_to_heap_only ctx ptr then + (* Ask for BlobSize from the base address (the second component being set to true) in order to avoid BlobSize giving us bot *) + ctx.ask (Queries.BlobSize {exp = ptr; base_address = true}) + else + match ctx.ask (Queries.MayPointTo ptr) with + | a when not (Queries.AD.is_top a) -> + let pts_list = Queries.AD.elements a in + let pts_elems_to_sizes (addr: Queries.AD.elt) = + begin match addr with + | Addr (v, _) -> + begin match v.vtype with + | TArray (item_typ, _, _) -> + let item_typ_size_in_bytes = size_of_type_in_bytes item_typ in + begin match ctx.ask (Queries.EvalLength ptr) with + | `Lifted arr_len -> + let arr_len_casted = ID.cast_to (Cilfacade.ptrdiff_ikind ()) arr_len in + begin + try `Lifted (ID.mul item_typ_size_in_bytes arr_len_casted) + with IntDomain.ArithmeticOnIntegerBot _ -> `Bot + end + | `Bot -> `Bot + | `Top -> `Top + end + | _ -> + let type_size_in_bytes = size_of_type_in_bytes v.vtype in + `Lifted type_size_in_bytes + end + | _ -> `Top + end + in + (* Map each points-to-set element to its size *) + let pts_sizes = List.map pts_elems_to_sizes pts_list in + (* Take the smallest of all sizes that ptr's contents may have *) + begin match pts_sizes with + | [] -> `Bot + | [x] -> x + | x::xs -> List.fold_left ValueDomainQueries.ID.join x xs + end + | _ -> + (M.warn "Pointer %a has a points-to-set of top. An invalid memory access might occur" d_exp ptr; + `Top) let special ctx (lv:lval option) (f: varinfo) (args: exp list) = let invalidate_ret_lv st = match lv with @@ -2073,13 +2131,32 @@ struct let st: store = ctx.local in let gs = ctx.global in let desc = LF.find f in - let memory_copying dst src = + let memory_copying dst src n = + let dest_size = get_size_of_ptr_target ctx dst in + let n_intdom = match n with + | Some exp -> ctx.ask (Queries.EvalInt exp) + | None -> `Bot + in + let dest_size_equal_n = + match dest_size, n_intdom with + | `Top, `Top -> true + | `Bot, `Bot -> true + | `Lifted ds, `Lifted n -> + let casted_ds = ID.cast_to (Cilfacade.ptrdiff_ikind ()) ds in + let casted_n = ID.cast_to (Cilfacade.ptrdiff_ikind ()) n in + let ds_eq_n = ID.eq casted_ds casted_n in + begin match ID.to_bool ds_eq_n with + | Some b -> b + | None -> false + end + | _, _ -> false + in let dest_a, dest_typ = addr_type_of_exp dst in let src_lval = mkMem ~addr:(Cil.stripCasts src) ~off:NoOffset in let src_typ = eval_lv (Analyses.ask_of_ctx ctx) gs st src_lval |> AD.type_of in (* when src and destination type coincide, take value from the source, otherwise use top *) - let value = if typeSig dest_typ = typeSig src_typ then + let value = if (typeSig dest_typ = typeSig src_typ) && dest_size_equal_n then let src_cast_lval = mkMem ~addr:(Cilfacade.mkCast ~e:src ~newt:(TPtr (dest_typ, []))) ~off:NoOffset in eval_rv (Analyses.ask_of_ctx ctx) gs st (Lval src_cast_lval) else @@ -2140,13 +2217,13 @@ struct let value = VD.zero_init_value dest_typ in set ~ctx (Analyses.ask_of_ctx ctx) gs st dest_a dest_typ value | Memcpy { dest = dst; src; n; }, _ -> (* TODO: use n *) - memory_copying dst src + memory_copying dst src (Some n) (* strcpy(dest, src); *) | Strcpy { dest = dst; src; n = None }, _ -> let dest_a, dest_typ = addr_type_of_exp dst in (* when dest surely isn't a string literal, try copying src to dest *) if AD.string_writing_defined dest_a then - memory_copying dst src + memory_copying dst src None else (* else return top (after a warning was issued) *) set ~ctx (Analyses.ask_of_ctx ctx) gs st dest_a dest_typ (VD.top_value (unrollType dest_typ)) From 48f2cfedda0a61517a69e012dfc07a08fe3646cb Mon Sep 17 00:00:00 2001 From: Stanimir Bozhilov Date: Thu, 5 Oct 2023 14:00:18 +0200 Subject: [PATCH 072/140] Add test case for UAF due to bad memcpy --- .../74-use_after_free/16-uaf-packed-struct.c | 40 +++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 tests/regression/74-use_after_free/16-uaf-packed-struct.c diff --git a/tests/regression/74-use_after_free/16-uaf-packed-struct.c b/tests/regression/74-use_after_free/16-uaf-packed-struct.c new file mode 100644 index 0000000000..e10aa28486 --- /dev/null +++ b/tests/regression/74-use_after_free/16-uaf-packed-struct.c @@ -0,0 +1,40 @@ +// PARAM: --set ana.activated[+] useAfterFree +#include +#include + +struct A { + unsigned char a; + unsigned char b:2; + unsigned char c:2; + unsigned char pad1[2]; + unsigned int d; + unsigned char e; + unsigned char pad2[3]; +} __attribute__((packed)); + +struct A d; +int main(void) +{ + struct A *p; + p = malloc(12); + d.a = 1; + d.b = 2; + d.c = 3; + d.d = 4; + d.e = 5; + memcpy(p, &d, 4); + if (p->a != 1) { + free(p); + } + if (p->b != 2) {//WARN + free(p);//WARN + } + if (p->c != 3) {//WARN + free(p);//WARN + } + if (p->d != 4) { //WARN + free(p);//WARN + } + free(p);//WARN +} + From 753b5c1661009bbfa6542fd64ca3d6de62231a34 Mon Sep 17 00:00:00 2001 From: Stanimir Bozhilov Date: Thu, 5 Oct 2023 14:02:33 +0200 Subject: [PATCH 073/140] Check offsets of dereferenced lvalues as well --- src/analyses/memOutOfBounds.ml | 65 +++++++++++++++++++++++++++++++--- 1 file changed, 61 insertions(+), 4 deletions(-) diff --git a/src/analyses/memOutOfBounds.ml b/src/analyses/memOutOfBounds.ml index 8a2ca12467..d555db968d 100644 --- a/src/analyses/memOutOfBounds.ml +++ b/src/analyses/memOutOfBounds.ml @@ -122,9 +122,9 @@ struct | x::xs -> List.fold_left VDQ.ID.join x xs end | _ -> - set_mem_safety_flag InvalidDeref; - M.warn "Pointer %a has a points-to-set of top. An invalid memory access might occur" d_exp ptr; - `Top + (set_mem_safety_flag InvalidDeref; + M.warn "Pointer %a has a points-to-set of top. An invalid memory access might occur" d_exp ptr; + `Top) let get_ptr_deref_type ptr_typ = match ptr_typ with @@ -165,6 +165,32 @@ struct with IntDomain.ArithmeticOnIntegerBot _ -> ID.bot_of @@ Cilfacade.ptrdiff_ikind () end + let rec cil_offs_to_idx ctx typ offs = + match offs with + | NoOffset -> intdom_of_int 0 + | Field (field, o) -> + let field_as_offset = Field (field, NoOffset) in + let bits_offset, _size = GoblintCil.bitsOffset (TComp (field.fcomp, [])) field_as_offset in + let bytes_offset = intdom_of_int (bits_offset / 8) in + let remaining_offset = cil_offs_to_idx ctx field.ftype o in + begin + try ID.add bytes_offset remaining_offset + with IntDomain.ArithmeticOnIntegerBot _ -> ID.bot_of @@ Cilfacade.ptrdiff_ikind () + end + | Index (x, o) -> + begin try + begin match ctx.ask (Queries.EvalInt x) with + | `Top -> ID.top_of @@ Cilfacade.ptrdiff_ikind () + | `Bot -> ID.bot_of @@ Cilfacade.ptrdiff_ikind () + | `Lifted eval_x -> + let typ_size_in_bytes = size_of_type_in_bytes typ in + let bytes_offset = ID.mul typ_size_in_bytes eval_x in + let remaining_offset = cil_offs_to_idx ctx typ o in + ID.add bytes_offset remaining_offset + end + with IntDomain.ArithmeticOnIntegerBot _ -> ID.bot_of @@ Cilfacade.ptrdiff_ikind () + end + let check_unknown_addr_deref ctx ptr = let may_contain_unknown_addr = match ctx.ask (Queries.EvalValue ptr) with @@ -245,7 +271,38 @@ struct match lval, is_implicitly_derefed with | (Var _, _), false -> () | (Var v, _), true -> check_no_binop_deref ctx (Lval lval) - | (Mem e, _), _ -> + | (Mem e, o), _ -> + let ptr_deref_type = get_ptr_deref_type @@ typeOf e in + let offs_intdom = begin match ptr_deref_type with + | Some t -> cil_offs_to_idx ctx t o + | None -> ID.bot_of @@ Cilfacade.ptrdiff_ikind () + end in + let e_size = get_size_of_ptr_target ctx e in + let () = begin match e_size with + | `Top -> + (set_mem_safety_flag InvalidDeref; + M.warn "Size of lval dereference expression %a is top. Out-of-bounds memory access may occur" d_exp e) + | `Bot -> + (set_mem_safety_flag InvalidDeref; + M.warn "Size of lval dereference expression %a is bot. Out-of-bounds memory access may occur" d_exp e) + | `Lifted es -> + let casted_es = ID.cast_to (Cilfacade.ptrdiff_ikind ()) es in + let one = intdom_of_int 1 in + let casted_es = ID.sub casted_es one in + let casted_offs = ID.cast_to (Cilfacade.ptrdiff_ikind ()) offs_intdom in + let ptr_size_lt_offs = ID.lt casted_es casted_offs in + let behavior = Undefined MemoryOutOfBoundsAccess in + let cwe_number = 823 in + begin match ID.to_bool ptr_size_lt_offs with + | Some true -> + (set_mem_safety_flag InvalidDeref; + M.warn ~category:(Behavior behavior) ~tags:[CWE cwe_number] "Size of lval dereference expression is %a (in bytes). It is offset by %a (in bytes). Memory out-of-bounds access must occur" ID.pretty casted_es ID.pretty casted_offs) + | Some false -> () + | None -> + (set_mem_safety_flag InvalidDeref; + M.warn ~category:(Behavior behavior) ~tags:[CWE cwe_number] "Could not compare size of lval dereference expression (%a) (in bytes) with offset by (%a) (in bytes). Memory out-of-bounds access might occur" ID.pretty casted_es ID.pretty casted_offs) + end + end in begin match e with | Lval (Var v, _) as lval_exp -> check_no_binop_deref ctx lval_exp | BinOp (binop, e1, e2, t) when binop = PlusPI || binop = MinusPI || binop = IndexPI -> From d68328163e07f228f44f50c0b9b27200ea631284 Mon Sep 17 00:00:00 2001 From: Stanimir Bozhilov Date: Thu, 5 Oct 2023 14:02:51 +0200 Subject: [PATCH 074/140] Add regr. test case for OOB due to too large lval offset --- .../77-mem-oob/13-mem-oob-packed-struct.c | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 tests/regression/77-mem-oob/13-mem-oob-packed-struct.c diff --git a/tests/regression/77-mem-oob/13-mem-oob-packed-struct.c b/tests/regression/77-mem-oob/13-mem-oob-packed-struct.c new file mode 100644 index 0000000000..552cd1bb0b --- /dev/null +++ b/tests/regression/77-mem-oob/13-mem-oob-packed-struct.c @@ -0,0 +1,33 @@ +// PARAM: --set ana.activated[+] memOutOfBounds --enable ana.int.interval +#include + +struct A { + unsigned char a; + unsigned char b:2; + unsigned char c:2; + unsigned char d; +} __attribute__((packed)); + +int main(void) +{ + struct A *p; + p = malloc(2); + p->a = 1; + if (p->a != 1) { + free(p); + } + p->b = 2; + if (p->b != 2) { + free(p); + } + p->c = 3; + if (p->c != 3) { + free(p); + } + p->d = 4; //WARN + if (p->d != 4) {//WARN + free(p); + } + free(p); +} + From d723fdef0bf9e17625c141ed44a0e9d271e0609d Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 5 Oct 2023 15:48:41 +0300 Subject: [PATCH 075/140] Extract widely used modules to common dune library --- src/{util => common}/afterConfig.ml | 0 src/{framework => common}/analysisState.ml | 0 src/{cdomains => common}/basetype.ml | 0 src/{util => common}/cilType.ml | 0 src/{util => common}/cilfacade.ml | 0 src/{util => common}/cilfacade0.ml | 0 src/{framework => common}/controlSpecC.ml | 0 src/{framework => common}/controlSpecC.mli | 0 src/common/dune | 28 ++++++++++++++++++++++ src/{framework => common}/edge.ml | 0 src/{util => common}/gobConfig.ml | 0 src/{util => common}/gobFormat.ml | 0 src/{util => common}/jsonSchema.ml | 0 src/{domains => common}/lattice.ml | 0 src/{util => common}/lazyEval.ml | 0 src/{util => common}/messageCategory.ml | 0 src/{util => common}/messageUtil.ml | 0 src/{util => common}/messages.ml | 0 src/{framework => common}/myCFG.ml | 0 src/{domains => common}/myCheck.ml | 0 src/{framework => common}/node.ml | 0 src/{framework => common}/node0.ml | 0 src/{util => common}/options.ml | 0 src/{util => common}/options.schema.json | 0 src/{domains => common}/printable.ml | 0 src/{util => common}/resettableLazy.ml | 0 src/{util => common}/resettableLazy.mli | 0 src/{util => common}/richVarinfo.ml | 0 src/{util => common}/richVarinfo.mli | 0 src/{util => common}/timing.ml | 0 src/{util => common}/tracing.ml | 0 src/{incremental => common}/updateCil0.ml | 0 src/{util => common}/xmlUtil.ml | 0 src/dune | 3 +-- 34 files changed, 29 insertions(+), 2 deletions(-) rename src/{util => common}/afterConfig.ml (100%) rename src/{framework => common}/analysisState.ml (100%) rename src/{cdomains => common}/basetype.ml (100%) rename src/{util => common}/cilType.ml (100%) rename src/{util => common}/cilfacade.ml (100%) rename src/{util => common}/cilfacade0.ml (100%) rename src/{framework => common}/controlSpecC.ml (100%) rename src/{framework => common}/controlSpecC.mli (100%) create mode 100644 src/common/dune rename src/{framework => common}/edge.ml (100%) rename src/{util => common}/gobConfig.ml (100%) rename src/{util => common}/gobFormat.ml (100%) rename src/{util => common}/jsonSchema.ml (100%) rename src/{domains => common}/lattice.ml (100%) rename src/{util => common}/lazyEval.ml (100%) rename src/{util => common}/messageCategory.ml (100%) rename src/{util => common}/messageUtil.ml (100%) rename src/{util => common}/messages.ml (100%) rename src/{framework => common}/myCFG.ml (100%) rename src/{domains => common}/myCheck.ml (100%) rename src/{framework => common}/node.ml (100%) rename src/{framework => common}/node0.ml (100%) rename src/{util => common}/options.ml (100%) rename src/{util => common}/options.schema.json (100%) rename src/{domains => common}/printable.ml (100%) rename src/{util => common}/resettableLazy.ml (100%) rename src/{util => common}/resettableLazy.mli (100%) rename src/{util => common}/richVarinfo.ml (100%) rename src/{util => common}/richVarinfo.mli (100%) rename src/{util => common}/timing.ml (100%) rename src/{util => common}/tracing.ml (100%) rename src/{incremental => common}/updateCil0.ml (100%) rename src/{util => common}/xmlUtil.ml (100%) diff --git a/src/util/afterConfig.ml b/src/common/afterConfig.ml similarity index 100% rename from src/util/afterConfig.ml rename to src/common/afterConfig.ml diff --git a/src/framework/analysisState.ml b/src/common/analysisState.ml similarity index 100% rename from src/framework/analysisState.ml rename to src/common/analysisState.ml diff --git a/src/cdomains/basetype.ml b/src/common/basetype.ml similarity index 100% rename from src/cdomains/basetype.ml rename to src/common/basetype.ml diff --git a/src/util/cilType.ml b/src/common/cilType.ml similarity index 100% rename from src/util/cilType.ml rename to src/common/cilType.ml diff --git a/src/util/cilfacade.ml b/src/common/cilfacade.ml similarity index 100% rename from src/util/cilfacade.ml rename to src/common/cilfacade.ml diff --git a/src/util/cilfacade0.ml b/src/common/cilfacade0.ml similarity index 100% rename from src/util/cilfacade0.ml rename to src/common/cilfacade0.ml diff --git a/src/framework/controlSpecC.ml b/src/common/controlSpecC.ml similarity index 100% rename from src/framework/controlSpecC.ml rename to src/common/controlSpecC.ml diff --git a/src/framework/controlSpecC.mli b/src/common/controlSpecC.mli similarity index 100% rename from src/framework/controlSpecC.mli rename to src/common/controlSpecC.mli diff --git a/src/common/dune b/src/common/dune new file mode 100644 index 0000000000..03a93a3030 --- /dev/null +++ b/src/common/dune @@ -0,0 +1,28 @@ +(include_subdirs no) + +(library + (name goblint_common) + (public_name goblint.common) + (wrapped false) ; TODO: wrap + (libraries + batteries + zarith + goblint_std + goblint-cil + fpath + yojson + json-data-encoding + cpu + goblint_timing + goblint_build_info + goblint.sites + qcheck-core.runner) + (flags :standard -open Goblint_std) + (preprocess + (pps + ppx_deriving.std + ppx_deriving_hash + ppx_deriving_yojson + ppx_blob)) + (preprocessor_deps (file options.schema.json))) + diff --git a/src/framework/edge.ml b/src/common/edge.ml similarity index 100% rename from src/framework/edge.ml rename to src/common/edge.ml diff --git a/src/util/gobConfig.ml b/src/common/gobConfig.ml similarity index 100% rename from src/util/gobConfig.ml rename to src/common/gobConfig.ml diff --git a/src/util/gobFormat.ml b/src/common/gobFormat.ml similarity index 100% rename from src/util/gobFormat.ml rename to src/common/gobFormat.ml diff --git a/src/util/jsonSchema.ml b/src/common/jsonSchema.ml similarity index 100% rename from src/util/jsonSchema.ml rename to src/common/jsonSchema.ml diff --git a/src/domains/lattice.ml b/src/common/lattice.ml similarity index 100% rename from src/domains/lattice.ml rename to src/common/lattice.ml diff --git a/src/util/lazyEval.ml b/src/common/lazyEval.ml similarity index 100% rename from src/util/lazyEval.ml rename to src/common/lazyEval.ml diff --git a/src/util/messageCategory.ml b/src/common/messageCategory.ml similarity index 100% rename from src/util/messageCategory.ml rename to src/common/messageCategory.ml diff --git a/src/util/messageUtil.ml b/src/common/messageUtil.ml similarity index 100% rename from src/util/messageUtil.ml rename to src/common/messageUtil.ml diff --git a/src/util/messages.ml b/src/common/messages.ml similarity index 100% rename from src/util/messages.ml rename to src/common/messages.ml diff --git a/src/framework/myCFG.ml b/src/common/myCFG.ml similarity index 100% rename from src/framework/myCFG.ml rename to src/common/myCFG.ml diff --git a/src/domains/myCheck.ml b/src/common/myCheck.ml similarity index 100% rename from src/domains/myCheck.ml rename to src/common/myCheck.ml diff --git a/src/framework/node.ml b/src/common/node.ml similarity index 100% rename from src/framework/node.ml rename to src/common/node.ml diff --git a/src/framework/node0.ml b/src/common/node0.ml similarity index 100% rename from src/framework/node0.ml rename to src/common/node0.ml diff --git a/src/util/options.ml b/src/common/options.ml similarity index 100% rename from src/util/options.ml rename to src/common/options.ml diff --git a/src/util/options.schema.json b/src/common/options.schema.json similarity index 100% rename from src/util/options.schema.json rename to src/common/options.schema.json diff --git a/src/domains/printable.ml b/src/common/printable.ml similarity index 100% rename from src/domains/printable.ml rename to src/common/printable.ml diff --git a/src/util/resettableLazy.ml b/src/common/resettableLazy.ml similarity index 100% rename from src/util/resettableLazy.ml rename to src/common/resettableLazy.ml diff --git a/src/util/resettableLazy.mli b/src/common/resettableLazy.mli similarity index 100% rename from src/util/resettableLazy.mli rename to src/common/resettableLazy.mli diff --git a/src/util/richVarinfo.ml b/src/common/richVarinfo.ml similarity index 100% rename from src/util/richVarinfo.ml rename to src/common/richVarinfo.ml diff --git a/src/util/richVarinfo.mli b/src/common/richVarinfo.mli similarity index 100% rename from src/util/richVarinfo.mli rename to src/common/richVarinfo.mli diff --git a/src/util/timing.ml b/src/common/timing.ml similarity index 100% rename from src/util/timing.ml rename to src/common/timing.ml diff --git a/src/util/tracing.ml b/src/common/tracing.ml similarity index 100% rename from src/util/tracing.ml rename to src/common/tracing.ml diff --git a/src/incremental/updateCil0.ml b/src/common/updateCil0.ml similarity index 100% rename from src/incremental/updateCil0.ml rename to src/common/updateCil0.ml diff --git a/src/util/xmlUtil.ml b/src/common/xmlUtil.ml similarity index 100% rename from src/util/xmlUtil.ml rename to src/common/xmlUtil.ml diff --git a/src/dune b/src/dune index 5fdf58a5b2..df19f85340 100644 --- a/src/dune +++ b/src/dune @@ -7,7 +7,7 @@ (name goblint_lib) (public_name goblint.lib) (modules :standard \ goblint mainspec privPrecCompare apronPrecCompare messagesCompare) - (libraries goblint.sites goblint.build-info goblint-cil.all-features batteries.unthreaded qcheck-core.runner sha json-data-encoding jsonrpc cpu arg-complete fpath yaml yaml.unix uuidm goblint_timing catapult goblint_backtrace fileutils goblint_std + (libraries goblint.sites goblint.build-info goblint-cil.all-features batteries.unthreaded qcheck-core.runner sha json-data-encoding jsonrpc cpu arg-complete fpath yaml yaml.unix uuidm goblint_timing catapult goblint_backtrace fileutils goblint_std goblint_common ; Conditionally compile based on whether apron optional dependency is installed or not. ; Alternative dependencies seem like the only way to optionally depend on optional dependencies. ; See: https://dune.readthedocs.io/en/stable/concepts.html#alternative-dependencies. @@ -61,7 +61,6 @@ (ocamlopt_flags :standard -no-float-const-prop) (preprocess (pps ppx_deriving.std ppx_deriving_hash ppx_deriving_yojson ppx_blob)) - (preprocessor_deps (file util/options.schema.json)) (instrumentation (backend bisect_ppx)) ) From 22e4df53b11aa16dc676a690f131321f2112523b Mon Sep 17 00:00:00 2001 From: Stanimir Bozhilov Date: Thu, 5 Oct 2023 15:24:47 +0200 Subject: [PATCH 076/140] Fix exceptions due to ID ops --- src/analyses/base.ml | 6 +++++- src/analyses/memOutOfBounds.ml | 9 +++++++-- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/src/analyses/base.ml b/src/analyses/base.ml index 2d779b8d85..b6cc5c29cf 100644 --- a/src/analyses/base.ml +++ b/src/analyses/base.ml @@ -2144,7 +2144,11 @@ struct | `Lifted ds, `Lifted n -> let casted_ds = ID.cast_to (Cilfacade.ptrdiff_ikind ()) ds in let casted_n = ID.cast_to (Cilfacade.ptrdiff_ikind ()) n in - let ds_eq_n = ID.eq casted_ds casted_n in + let ds_eq_n = + begin try ID.eq casted_ds casted_n + with IntDomain.ArithmeticOnIntegerBot _ -> ID.bot_of @@ Cilfacade.ptrdiff_ikind () + end + in begin match ID.to_bool ds_eq_n with | Some b -> b | None -> false diff --git a/src/analyses/memOutOfBounds.ml b/src/analyses/memOutOfBounds.ml index d555db968d..68dae1d89a 100644 --- a/src/analyses/memOutOfBounds.ml +++ b/src/analyses/memOutOfBounds.ml @@ -184,7 +184,8 @@ struct | `Bot -> ID.bot_of @@ Cilfacade.ptrdiff_ikind () | `Lifted eval_x -> let typ_size_in_bytes = size_of_type_in_bytes typ in - let bytes_offset = ID.mul typ_size_in_bytes eval_x in + let casted_eval_x = ID.cast_to (Cilfacade.ptrdiff_ikind ()) eval_x in + let bytes_offset = ID.mul typ_size_in_bytes casted_eval_x in let remaining_offset = cil_offs_to_idx ctx typ o in ID.add bytes_offset remaining_offset end @@ -290,7 +291,11 @@ struct let one = intdom_of_int 1 in let casted_es = ID.sub casted_es one in let casted_offs = ID.cast_to (Cilfacade.ptrdiff_ikind ()) offs_intdom in - let ptr_size_lt_offs = ID.lt casted_es casted_offs in + let ptr_size_lt_offs = + begin try ID.lt casted_es casted_offs + with IntDomain.ArithmeticOnIntegerBot _ -> ID.bot_of @@ Cilfacade.ptrdiff_ikind () + end + in let behavior = Undefined MemoryOutOfBoundsAccess in let cwe_number = 823 in begin match ID.to_bool ptr_size_lt_offs with From b9c213441f2ef03ce02173fa323650ebe234c080 Mon Sep 17 00:00:00 2001 From: Stanimir Bozhilov Date: Fri, 6 Oct 2023 23:54:55 +0300 Subject: [PATCH 077/140] Fix size check in `memory_copying` Co-authored-by: Michael Schwarz --- src/analyses/base.ml | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/src/analyses/base.ml b/src/analyses/base.ml index b6cc5c29cf..6aaf25944e 100644 --- a/src/analyses/base.ml +++ b/src/analyses/base.ml @@ -2139,21 +2139,16 @@ struct in let dest_size_equal_n = match dest_size, n_intdom with - | `Top, `Top -> true - | `Bot, `Bot -> true | `Lifted ds, `Lifted n -> let casted_ds = ID.cast_to (Cilfacade.ptrdiff_ikind ()) ds in let casted_n = ID.cast_to (Cilfacade.ptrdiff_ikind ()) n in let ds_eq_n = begin try ID.eq casted_ds casted_n - with IntDomain.ArithmeticOnIntegerBot _ -> ID.bot_of @@ Cilfacade.ptrdiff_ikind () + with IntDomain.ArithmeticOnIntegerBot _ -> ID.top_of @@ Cilfacade.ptrdiff_ikind () end in - begin match ID.to_bool ds_eq_n with - | Some b -> b - | None -> false - end - | _, _ -> false + Option.value ~default:false ID.to_bool ds_eq_n + | _ -> false in let dest_a, dest_typ = addr_type_of_exp dst in let src_lval = mkMem ~addr:(Cil.stripCasts src) ~off:NoOffset in From 625e90b308159da7407f0fef01cd863bfc662d36 Mon Sep 17 00:00:00 2001 From: Stanimir Bozhilov Date: Fri, 6 Oct 2023 23:56:11 +0300 Subject: [PATCH 078/140] Use `Option.map_default` instead of `match` Co-authored-by: Michael Schwarz --- src/analyses/base.ml | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/analyses/base.ml b/src/analyses/base.ml index 6aaf25944e..cc5ddc9c9d 100644 --- a/src/analyses/base.ml +++ b/src/analyses/base.ml @@ -2133,10 +2133,7 @@ struct let desc = LF.find f in let memory_copying dst src n = let dest_size = get_size_of_ptr_target ctx dst in - let n_intdom = match n with - | Some exp -> ctx.ask (Queries.EvalInt exp) - | None -> `Bot - in + let n_intdom = Option.map_default (fun exp -> ctx.ask (Queries.EvalInt exp)) `Bot n in let dest_size_equal_n = match dest_size, n_intdom with | `Lifted ds, `Lifted n -> From fbab25ec49ecee2727f9675e36e5b3116b4c1d91 Mon Sep 17 00:00:00 2001 From: Stanimir Bozhilov Date: Fri, 6 Oct 2023 23:56:59 +0300 Subject: [PATCH 079/140] Use `_` in place of unused offset in lambda Co-authored-by: Michael Schwarz --- src/analyses/base.ml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/analyses/base.ml b/src/analyses/base.ml index cc5ddc9c9d..df67d1afe4 100644 --- a/src/analyses/base.ml +++ b/src/analyses/base.ml @@ -2058,7 +2058,7 @@ struct match ctx.ask (Queries.MayPointTo ptr) with | a when not (Queries.AD.is_top a)-> Queries.AD.for_all (function - | Addr (v, o) -> ctx.ask (Queries.IsHeapVar v) + | Addr (v, _) -> ctx.ask (Queries.IsHeapVar v) | _ -> false ) a | _ -> false From 91aeee732f1f97afdb406e189176f22c46049ff1 Mon Sep 17 00:00:00 2001 From: Stanimir Bozhilov Date: Fri, 6 Oct 2023 23:57:46 +0300 Subject: [PATCH 080/140] Set `Cabs2cil.addNestedScopeAttr` based on the Goblint config option Co-authored-by: Michael Schwarz --- src/util/cilfacade.ml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/util/cilfacade.ml b/src/util/cilfacade.ml index 432b623464..3b00365abf 100644 --- a/src/util/cilfacade.ml +++ b/src/util/cilfacade.ml @@ -41,8 +41,7 @@ let init_options () = Mergecil.merge_inlines := get_bool "cil.merge.inlines"; Cil.cstd := Cil.cstd_of_string (get_string "cil.cstd"); Cil.gnu89inline := get_bool "cil.gnu89inline"; - if get_bool "cil.addNestedScopeAttr" then - Cabs2cil.addNestedScopeAttr := true + Cabs2cil.addNestedScopeAttr := get_bool "cil.addNestedScopeAttr"; let init () = initCIL (); From 992e5c0b183326d8a3acc102fd40c99e110c140d Mon Sep 17 00:00:00 2001 From: Stanimir Bozhilov Date: Fri, 6 Oct 2023 23:04:44 +0200 Subject: [PATCH 081/140] Remove extra semicolon --- src/util/cilfacade.ml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/util/cilfacade.ml b/src/util/cilfacade.ml index 3b00365abf..ba57074e5a 100644 --- a/src/util/cilfacade.ml +++ b/src/util/cilfacade.ml @@ -41,7 +41,7 @@ let init_options () = Mergecil.merge_inlines := get_bool "cil.merge.inlines"; Cil.cstd := Cil.cstd_of_string (get_string "cil.cstd"); Cil.gnu89inline := get_bool "cil.gnu89inline"; - Cabs2cil.addNestedScopeAttr := get_bool "cil.addNestedScopeAttr"; + Cabs2cil.addNestedScopeAttr := get_bool "cil.addNestedScopeAttr" let init () = initCIL (); From cc351e04e745b11aaab409a60b7d2dc7a7c32eab Mon Sep 17 00:00:00 2001 From: Stanimir Bozhilov Date: Fri, 6 Oct 2023 23:05:00 +0200 Subject: [PATCH 082/140] Use `Option.default` in place of `Option.value` --- src/analyses/base.ml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/analyses/base.ml b/src/analyses/base.ml index df67d1afe4..f5da725226 100644 --- a/src/analyses/base.ml +++ b/src/analyses/base.ml @@ -2144,7 +2144,7 @@ struct with IntDomain.ArithmeticOnIntegerBot _ -> ID.top_of @@ Cilfacade.ptrdiff_ikind () end in - Option.value ~default:false ID.to_bool ds_eq_n + Option.default false (ID.to_bool ds_eq_n) | _ -> false in let dest_a, dest_typ = addr_type_of_exp dst in From de0220baf762f69ba6f0da19299ce568b243bed4 Mon Sep 17 00:00:00 2001 From: Stanimir Bozhilov Date: Fri, 6 Oct 2023 23:09:46 +0200 Subject: [PATCH 083/140] Use `AD.exists` to warn about non-local vars in address set instead of using `AD.iter` --- src/analyses/base.ml | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/src/analyses/base.ml b/src/analyses/base.ml index f5da725226..908dc88401 100644 --- a/src/analyses/base.ml +++ b/src/analyses/base.ml @@ -1052,17 +1052,14 @@ struct AnalysisStateUtil.set_mem_safety_flag InvalidDeref; M.warn ~category:M.Category.Behavior.Undefined.nullpointer_dereference ~tags:[CWE 476] "May dereference NULL pointer" ); - (* Warn if any of the addresses contains a non-local variable *) - AD.iter (function - | AD.Addr.Addr (v,o) -> - if not (CPA.mem v st.cpa) && not (is_global a v) then ( - (* TODO: Not the smartest move to set the global flag within an iter *) - (* TODO: We can resort to using AD.exists instead *) - AnalysisStateUtil.set_mem_safety_flag InvalidDeref; - M.warn "lval %a points to non-local variable %a. Invalid pointer dereference may occur" d_lval lval CilType.Varinfo.pretty v - ) - | _ -> () - ) adr + (* Warn if any of the addresses contains a non-local and non-global variable *) + if AD.exists (function + | AD.Addr.Addr (v, _) -> not (CPA.mem v st.cpa) && not (is_global a v) + | _ -> false + ) adr then ( + AnalysisStateUtil.set_mem_safety_flag InvalidDeref; + M.warn "lval %a points to a non-local variable. Invalid pointer dereference may occur" d_lval lval + ) ); AD.map (add_offset_varinfo (convert_offset a gs st ofs)) adr | _ -> From fd5237a6dfdd68f1cd6791030dd43227e9ed77fc Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Mon, 9 Oct 2023 11:40:54 +0300 Subject: [PATCH 084/140] Add 68-longjmp/56-longjmp-top extracted from concrat --- tests/regression/68-longjmp/56-longjmp-top.c | 21 ++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 tests/regression/68-longjmp/56-longjmp-top.c diff --git a/tests/regression/68-longjmp/56-longjmp-top.c b/tests/regression/68-longjmp/56-longjmp-top.c new file mode 100644 index 0000000000..4a12a43792 --- /dev/null +++ b/tests/regression/68-longjmp/56-longjmp-top.c @@ -0,0 +1,21 @@ +// Extracted from concrat/pigz. +#include +#include +#include + +pthread_key_t buf_key; + +int main() { + jmp_buf buf; + pthread_setspecific(buf_key, &buf); + + if (!setjmp(buf)) { + jmp_buf *buf_ptr; + buf_ptr = pthread_getspecific(buf_key); + longjmp(*buf_ptr, 1); // TODO NO CRASH: problem?! + } + else { + __goblint_check(1); // reachable + } + return 0; +} From 2224e86ce5e770cedd4558cfff6379471424e743 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Mon, 9 Oct 2023 11:46:24 +0300 Subject: [PATCH 085/140] Fix longjmp crash on Uninitialized --- src/analyses/base.ml | 11 +++++++++-- tests/regression/68-longjmp/56-longjmp-top.c | 2 +- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/src/analyses/base.ml b/src/analyses/base.ml index 7b87d3ff51..2fda2540e8 100644 --- a/src/analyses/base.ml +++ b/src/analyses/base.ml @@ -1217,9 +1217,16 @@ struct if copied then M.warn ~category:(Behavior (Undefined Other)) "The jump buffer %a contains values that were copied here instead of being set by setjmp. This is Undefined Behavior." d_exp e; x - | y -> failwith (GobPretty.sprintf "problem?! is %a %a:\n state is %a" CilType.Exp.pretty e VD.pretty y D.pretty ctx.local) + | Top + | Bot -> + JmpBufDomain.JmpBufSet.top () + | y -> + M.debug ~category:Imprecise "EvalJmpBuf %a is %a, not JmpBuf." CilType.Exp.pretty e VD.pretty y; + JmpBufDomain.JmpBufSet.top () end - | _ -> failwith "problem?!" + | _ -> + M.debug ~category:Imprecise "EvalJmpBuf is not Address"; + JmpBufDomain.JmpBufSet.top () end | Q.EvalInt e -> query_evalint (Analyses.ask_of_ctx ctx) ctx.global ctx.local e diff --git a/tests/regression/68-longjmp/56-longjmp-top.c b/tests/regression/68-longjmp/56-longjmp-top.c index 4a12a43792..4d57b42fd3 100644 --- a/tests/regression/68-longjmp/56-longjmp-top.c +++ b/tests/regression/68-longjmp/56-longjmp-top.c @@ -12,7 +12,7 @@ int main() { if (!setjmp(buf)) { jmp_buf *buf_ptr; buf_ptr = pthread_getspecific(buf_key); - longjmp(*buf_ptr, 1); // TODO NO CRASH: problem?! + longjmp(*buf_ptr, 1); // NO CRASH: problem?! } else { __goblint_check(1); // reachable From c6f7180617d67f5e00845cfc80b2a6f7e78e9dda Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Mon, 9 Oct 2023 15:37:37 +0300 Subject: [PATCH 086/140] Add more duplicate library function checks --- src/analyses/libraryFunctions.ml | 40 ++++++++++++++++++++++++++++---- 1 file changed, 36 insertions(+), 4 deletions(-) diff --git a/src/analyses/libraryFunctions.ml b/src/analyses/libraryFunctions.ml index 1c509e7660..f30f40cbdf 100644 --- a/src/analyses/libraryFunctions.ml +++ b/src/analyses/libraryFunctions.ml @@ -994,11 +994,43 @@ let libraries = Hashtbl.of_list [ ("liblzma", liblzma_descs_list); ] +let libraries = + Hashtbl.map (fun library descs_list -> + let descs_tbl = Hashtbl.create 113 in + List.iter (fun (name, desc) -> + Hashtbl.modify_opt name (function + | None -> Some desc + | Some _ -> failwith (Format.sprintf "Library function %s specified multiple times in library %s" name library) + ) descs_tbl + ) descs_list; + descs_tbl + ) libraries + +let all_library_descs: (string, LibraryDesc.t) Hashtbl.t = + Hashtbl.fold (fun _ descs_tbl acc -> + Hashtbl.merge (fun name desc1 desc2 -> + match desc1, desc2 with + | Some _, Some _ -> failwith (Format.sprintf "Library function %s specified in multiple libraries" name) + | (Some _ as desc), None + | None, (Some _ as desc) -> desc + | None, None -> assert false + ) acc descs_tbl + ) libraries (Hashtbl.create 0) + let activated_library_descs: (string, LibraryDesc.t) Hashtbl.t ResettableLazy.t = + let union = + Hashtbl.merge (fun _ desc1 desc2 -> + match desc1, desc2 with + | (Some _ as desc), None + | None, (Some _ as desc) -> desc + | _, _ -> assert false + ) + in ResettableLazy.from_fun (fun () -> - let activated = List.unique (GobConfig.get_string_list "lib.activated") in - let desc_list = List.concat_map (Hashtbl.find libraries) activated in - Hashtbl.of_list desc_list + GobConfig.get_string_list "lib.activated" + |> List.unique + |> List.map (Hashtbl.find libraries) + |> List.fold_left union (Hashtbl.create 0) ) let reset_lazy () = @@ -1201,7 +1233,7 @@ let invalidate_actions = [ ] let () = List.iter (fun (x, _) -> - if Hashtbl.exists (fun _ b -> List.mem_assoc x b) libraries then + if Hashtbl.mem all_library_descs x then failwith ("You have added a function to invalidate_actions that already exists in libraries. Please undo this for function: " ^ x); ) invalidate_actions From 44e01f563bc6cf74399af4e4251456c54325a34e Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Mon, 9 Oct 2023 15:43:04 +0300 Subject: [PATCH 087/140] Remove duplicate library functions --- src/analyses/libraryFunctions.ml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/analyses/libraryFunctions.ml b/src/analyses/libraryFunctions.ml index f30f40cbdf..0360617171 100644 --- a/src/analyses/libraryFunctions.ml +++ b/src/analyses/libraryFunctions.ml @@ -244,7 +244,6 @@ let posix_descs_list: (string * LibraryDesc.t) list = LibraryDsl.[ ("symlink" , unknown [drop "oldpath" [r]; drop "newpath" [r];]); ("ftruncate", unknown [drop "fd" []; drop "length" []]); ("mkfifo", unknown [drop "pathname" [r]; drop "mode" []]); - ("ntohs", unknown [drop "netshort" []]); ("alarm", unknown [drop "seconds" []]); ("pwrite", unknown [drop "fd" []; drop "buf" [r]; drop "count" []; drop "offset" []]); ("hstrerror", unknown [drop "err" []]); @@ -275,7 +274,6 @@ let posix_descs_list: (string * LibraryDesc.t) list = LibraryDsl.[ ("lstat", unknown [drop "pathname" [r]; drop "statbuf" [w]]); ("fstat", unknown [drop "fd" []; drop "buf" [w]]); ("fstatat", unknown [drop "dirfd" []; drop "pathname" [r]; drop "buf" [w]; drop "flags" []]); - ("getpwnam", unknown [drop "name" [r]]); ("chdir", unknown [drop "path" [r]]); ("closedir", unknown [drop "dirp" [r]]); ("mkdir", unknown [drop "pathname" [r]; drop "mode" []]); @@ -295,7 +293,6 @@ let posix_descs_list: (string * LibraryDesc.t) list = LibraryDsl.[ ("freeaddrinfo", unknown [drop "res" [f_deep]]); ("getgid", unknown []); ("pselect", unknown [drop "nfds" []; drop "readdfs" [r]; drop "writedfs" [r]; drop "exceptfds" [r]; drop "timeout" [r]; drop "sigmask" [r]]); - ("strncasecmp", unknown [drop "s1" [r]; drop "s2" [r]; drop "n" []]); ("getnameinfo", unknown [drop "addr" [r_deep]; drop "addrlen" []; drop "host" [w]; drop "hostlen" []; drop "serv" [w]; drop "servlen" []; drop "flags" []]); ("strtok_r", unknown [drop "str" [r; w]; drop "delim" [r]; drop "saveptr" [r_deep; w_deep]]); (* deep accesses through saveptr if str is NULL: https://github.com/lattera/glibc/blob/895ef79e04a953cac1493863bcae29ad85657ee1/string/strtok_r.c#L31-L40 *) ("kill", unknown [drop "pid" []; drop "sig" []]); @@ -437,7 +434,6 @@ let pthread_descs_list: (string * LibraryDesc.t) list = LibraryDsl.[ ("pthread_attr_setschedpolicy", unknown [drop "attr" [r; w]; drop "policy" []]); ("pthread_condattr_init", unknown [drop "attr" [w]]); ("pthread_condattr_setclock", unknown [drop "attr" [w]; drop "clock_id" []]); - ("pthread_mutexattr_destroy", unknown [drop "attr" [f]]); ("pthread_attr_setschedparam", unknown [drop "attr" [r; w]; drop "param" [r]]); ("pthread_setaffinity_np", unknown [drop "thread" []; drop "cpusetsize" []; drop "cpuset" [r]]); ("pthread_getaffinity_np", unknown [drop "thread" []; drop "cpusetsize" []; drop "cpuset" [w]]); From 599bbb5ed55a7a8ab509271193e4c2df05dadbbe Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Mon, 9 Oct 2023 15:53:34 +0300 Subject: [PATCH 088/140] Refactor invalidate actions table --- src/analyses/libraryFunctions.ml | 38 +++++++++----------------------- 1 file changed, 11 insertions(+), 27 deletions(-) diff --git a/src/analyses/libraryFunctions.ml b/src/analyses/libraryFunctions.ml index 0360617171..aa279ff324 100644 --- a/src/analyses/libraryFunctions.ml +++ b/src/analyses/libraryFunctions.ml @@ -1228,32 +1228,16 @@ let invalidate_actions = [ "__goblint_assume_join", readsAll; ] -let () = List.iter (fun (x, _) -> - if Hashtbl.mem all_library_descs x then - failwith ("You have added a function to invalidate_actions that already exists in libraries. Please undo this for function: " ^ x); - ) invalidate_actions - -(* used by get_invalidate_action to make sure - * that hash of invalidates is built only once - * - * Hashtable from strings to functions of type (exp list -> exp list) -*) -let processed_table = ref None - -let get_invalidate_action name = - let tbl = match !processed_table with - | None -> begin - let hash = Hashtbl.create 113 in - let f (k, v) = Hashtbl.add hash k v in - List.iter f invalidate_actions; - processed_table := (Some hash); - hash - end - | Some x -> x - in - if Hashtbl.mem tbl name - then Some (Hashtbl.find tbl name) - else None +let invalidate_actions = + let tbl = Hashtbl.create 113 in + List.iter (fun (name, old_accesses) -> + Hashtbl.modify_opt name (function + | None when Hashtbl.mem all_library_descs name -> failwith (Format.sprintf "Library function %s specified both in libraries and invalidate actions" name) + | None -> Some old_accesses + | Some _ -> failwith (Format.sprintf "Library function %s specified multiple times in invalidate actions" name) + ) tbl + ) invalidate_actions; + tbl let lib_funs = ref (Set.String.of_list ["__raw_read_unlock"; "__raw_write_unlock"; "spin_trylock"]) @@ -1297,7 +1281,7 @@ let find f = match Hashtbl.find_option (ResettableLazy.force activated_library_descs) name with | Some desc -> desc | None -> - match get_invalidate_action name with + match Hashtbl.find_option invalidate_actions name with | Some old_accesses -> LibraryDesc.of_old old_accesses | None -> From 6fd299852648e1dde28eeb0b70e5684b9f471dab Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Mon, 9 Oct 2023 16:09:39 +0300 Subject: [PATCH 089/140] Fix references to options.schema.json --- .github/workflows/options.yml | 6 +++--- .readthedocs.yaml | 2 +- docs/user-guide/configuring.md | 2 +- src/common/options.ml | 2 +- src/goblint_lib.ml | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/options.yml b/.github/workflows/options.yml index b5f690a700..84906d4949 100644 --- a/.github/workflows/options.yml +++ b/.github/workflows/options.yml @@ -26,10 +26,10 @@ jobs: run: npm install -g ajv-cli - name: Migrate schema # https://github.com/ajv-validator/ajv-cli/issues/199 - run: ajv migrate -s src/util/options.schema.json + run: ajv migrate -s src/common/options.schema.json - name: Validate conf - run: ajv validate -s src/util/options.schema.json -d "conf/**/*.json" + run: ajv validate -s src/common/options.schema.json -d "conf/**/*.json" - name: Validate incremental tests - run: ajv validate -s src/util/options.schema.json -d "tests/incremental/*/*.json" + run: ajv validate -s src/common/options.schema.json -d "tests/incremental/*/*.json" diff --git a/.readthedocs.yaml b/.readthedocs.yaml index c9b41df49d..4827b825ef 100644 --- a/.readthedocs.yaml +++ b/.readthedocs.yaml @@ -20,4 +20,4 @@ build: - pip install json-schema-for-humans post_build: - mkdir _readthedocs/html/jsfh/ - - generate-schema-doc --config-file jsfh.yml src/util/options.schema.json _readthedocs/html/jsfh/ + - generate-schema-doc --config-file jsfh.yml src/common/options.schema.json _readthedocs/html/jsfh/ diff --git a/docs/user-guide/configuring.md b/docs/user-guide/configuring.md index 82e92f6fe7..348e15dac4 100644 --- a/docs/user-guide/configuring.md +++ b/docs/user-guide/configuring.md @@ -24,7 +24,7 @@ In `.vscode/settings.json` add the following: "/conf/*.json", "/tests/incremental/*/*.json" ], - "url": "/src/util/options.schema.json" + "url": "/src/common/options.schema.json" } ] } diff --git a/src/common/options.ml b/src/common/options.ml index d352c86465..c9bd41038f 100644 --- a/src/common/options.ml +++ b/src/common/options.ml @@ -1,4 +1,4 @@ -(** [src/util/options.schema.json] low-level access. *) +(** [src/common/options.schema.json] low-level access. *) open Json_schema diff --git a/src/goblint_lib.ml b/src/goblint_lib.ml index e009ecf86b..a108058291 100644 --- a/src/goblint_lib.ml +++ b/src/goblint_lib.ml @@ -49,7 +49,7 @@ module VarQuery = VarQuery (** {2 Configuration} Runtime configuration is represented as JSON. - Options are specified and documented by the JSON schema [src/util/options.schema.json]. *) + Options are specified and documented by the JSON schema [src/common/options.schema.json]. *) module GobConfig = GobConfig module AfterConfig = AfterConfig From 809f84b905a4b85f6e56d7fc74a5d252dfe90a5e Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Mon, 9 Oct 2023 16:12:52 +0300 Subject: [PATCH 090/140] Update Gobview for goblint.common --- gobview | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gobview b/gobview index b373d06174..41be36b548 160000 --- a/gobview +++ b/gobview @@ -1 +1 @@ -Subproject commit b373d06174667537b671f3122daf4ebd4b195aea +Subproject commit 41be36b54837b24e6de83740c34e810d3d1afdfb From 5aa420441c248a582b4484df170666b75fee5377 Mon Sep 17 00:00:00 2001 From: Michael Schwarz Date: Mon, 9 Oct 2023 16:20:50 +0200 Subject: [PATCH 091/140] Some ~15 more library functions (#1203) * More socket * `recvfrom` * `writev` / `readv` * `popen` * `stat` / `fstat` * `statfs` * `mount` / `umount` * Fix `select` Co-authored-by: Simmo Saan * Rm duplicate `fstat` Co-authored-by: Simmo Saan * Rm duplicates --------- Co-authored-by: Simmo Saan --- src/analyses/libraryFunctions.ml | 33 ++++++++++++++++---------------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/src/analyses/libraryFunctions.ml b/src/analyses/libraryFunctions.ml index 1c509e7660..c4d1acf76a 100644 --- a/src/analyses/libraryFunctions.ml +++ b/src/analyses/libraryFunctions.ml @@ -285,7 +285,9 @@ let posix_descs_list: (string * LibraryDesc.t) list = LibraryDsl.[ ("read", unknown [drop "fd" []; drop "buf" [w]; drop "count" []]); ("write", unknown [drop "fd" []; drop "buf" [r]; drop "count" []]); ("recv", unknown [drop "sockfd" []; drop "buf" [w]; drop "len" []; drop "flags" []]); + ("recvfrom", unknown [drop "sockfd" []; drop "buf" [w]; drop "len" []; drop "flags" []; drop "src_addr" [w_deep]; drop "addrlen" [r; w]]); ("send", unknown [drop "sockfd" []; drop "buf" [r]; drop "len" []; drop "flags" []]); + ("sendto", unknown [drop "sockfd" []; drop "buf" [r]; drop "len" []; drop "flags" []; drop "dest_addr" [r_deep]; drop "addrlen" []]); ("strdup", unknown [drop "s" [r]]); ("strndup", unknown [drop "s" [r]; drop "n" []]); ("syscall", unknown (drop "number" [] :: VarArgs (drop' [r; w]))); @@ -373,6 +375,18 @@ let posix_descs_list: (string * LibraryDesc.t) list = LibraryDsl.[ ("uname", unknown [drop "buf" [w_deep]]); ("strcasecmp", unknown [drop "s1" [r]; drop "s2" [r]]); ("strncasecmp", unknown [drop "s1" [r]; drop "s2" [r]; drop "n" []]); + ("connect", unknown [drop "sockfd" []; drop "sockaddr" [r_deep]; drop "addrlen" []]); + ("bind", unknown [drop "sockfd" []; drop "sockaddr" [r_deep]; drop "addrlen" []]); + ("listen", unknown [drop "sockfd" []; drop "backlog" []]); + ("select", unknown [drop "nfds" []; drop "readfds" [r; w]; drop "writefds" [r; w]; drop "exceptfds" [r; w]; drop "timeout" [r; w]]); + ("accept", unknown [drop "sockfd" []; drop "addr" [w_deep]; drop "addrlen" [r; w]]); + ("close", unknown [drop "fd" []]); + ("writev", unknown [drop "fd" []; drop "iov" [r_deep]; drop "iovcnt" []]); + ("readv", unknown [drop "fd" []; drop "iov" [w_deep]; drop "iovcnt" []]); + ("unlink", unknown [drop "pathname" [r]]); + ("popen", unknown [drop "command" [r]; drop "type" [r]]); + ("stat", unknown [drop "pathname" [r]; drop "statbuf" [w]]); + ("statfs", unknown [drop "path" [r]; drop "buf" [w]]); ] (** Pthread functions. *) @@ -588,6 +602,9 @@ let linux_userspace_descs_list: (string * LibraryDesc.t) list = LibraryDsl.[ ("fts_open", unknown [drop "path_argv" [r_deep]; drop "options" []; drop "compar" [s]]); (* TODO: use Call instead of Spawn *) ("fts_read", unknown [drop "ftsp" [r_deep; w_deep]]); ("fts_close", unknown [drop "ftsp" [f_deep]]); + ("mount", unknown [drop "source" [r]; drop "target" [r]; drop "filesystemtype" [r]; drop "mountflags" []; drop "data" [r]]); + ("umount", unknown [drop "target" [r]]); + ("umount2", unknown [drop "target" [r]; drop "flags" []]); ] let big_kernel_lock = AddrOf (Cil.var (Cilfacade.create_var (makeGlobalVar "[big kernel lock]" intType))) @@ -1100,7 +1117,6 @@ open Invalidate * We assume that no known functions that are reachable are executed/spawned. For that we use ThreadCreate above. *) (* WTF: why are argument numbers 1-indexed (in partition)? *) let invalidate_actions = [ - "connect", readsAll; (*safe*) "__printf_chk", readsAll;(*safe*) "printk", readsAll;(*safe*) "__mutex_init", readsAll;(*safe*) @@ -1118,23 +1134,17 @@ let invalidate_actions = [ "atoi__extinline", readsAll;(*safe*) "_IO_getc", writesAll;(*unsafe*) "pipe", writesAll;(*unsafe*) - "close", writesAll;(*unsafe*) "strerror_r", writesAll;(*unsafe*) "raise", writesAll;(*unsafe*) "_strlen", readsAll;(*safe*) "stat__extinline", writesAllButFirst 1 readsAll;(*drop 1*) "lstat__extinline", writesAllButFirst 1 readsAll;(*drop 1*) - "umount2", readsAll;(*safe*) "waitpid", readsAll;(*safe*) - "statfs", writes [1;3;4];(*keep [1;3;4]*) - "mount", readsAll;(*safe*) "__open_alias", readsAll;(*safe*) "__open_2", readsAll;(*safe*) "ioctl", writesAll;(*unsafe*) "fstat__extinline", writesAll;(*unsafe*) - "umount", readsAll;(*safe*) "scandir", writes [1;3;4];(*keep [1;3;4]*) - "unlink", readsAll;(*safe*) "sigwait", writesAllButFirst 1 readsAll;(*drop 1*) "bindtextdomain", readsAll;(*safe*) "textdomain", readsAll;(*safe*) @@ -1149,11 +1159,9 @@ let invalidate_actions = [ "svctcp_create", readsAll;(*safe*) "clntudp_bufcreate", writesAll;(*unsafe*) "authunix_create_default", readsAll;(*safe*) - "writev", readsAll;(*safe*) "clnt_broadcast", writesAll;(*unsafe*) "clnt_sperrno", readsAll;(*safe*) "pmap_unset", writesAll;(*unsafe*) - "bind", readsAll;(*safe*) "svcudp_create", readsAll;(*safe*) "svc_register", writesAll;(*unsafe*) "svc_run", writesAll;(*unsafe*) @@ -1162,18 +1170,13 @@ let invalidate_actions = [ "__builtin___vsnprintf_chk", writesAllButFirst 3 readsAll; (*drop 3*) "__error", readsAll; (*safe*) "__maskrune", writesAll; (*unsafe*) - "listen", readsAll; (*safe*) - "select", writes [1;5]; (*keep [1;5]*) - "accept", writesAll; (*keep [1]*) "times", writesAll; (*unsafe*) "timespec_get", writes [1]; "__tolower", readsAll; (*safe*) "signal", writesAll; (*unsafe*) - "popen", readsAll; (*safe*) "BF_cfb64_encrypt", writes [1;3;4;5]; (*keep [1;3;4,5]*) "BZ2_bzBuffToBuffDecompress", writes [3;4]; (*keep [3;4]*) "uncompress", writes [3;4]; (*keep [3;4]*) - "stat", writes [2]; (*keep [1]*) "__xstat", writes [3]; (*keep [1]*) "__lxstat", writes [3]; (*keep [1]*) "remove", readsAll; @@ -1181,8 +1184,6 @@ let invalidate_actions = [ "compress2", writes [3]; (*keep [3]*) "__toupper", readsAll; (*safe*) "BF_set_key", writes [3]; (*keep [3]*) - "sendto", writes [2;4]; (*keep [2;4]*) - "recvfrom", writes [4;5]; (*keep [4;5]*) "PL_NewHashTable", readsAll; (*safe*) "assert_failed", readsAll; (*safe*) "munmap", readsAll;(*safe*) From 85ce4b252b47aebc19574938f0db01635c93114c Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Tue, 10 Oct 2023 14:52:23 +0300 Subject: [PATCH 092/140] Add some missing library functions for concrat/sysbench --- src/analyses/libraryFunctions.ml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/analyses/libraryFunctions.ml b/src/analyses/libraryFunctions.ml index 03a984fede..b84ddc5ac5 100644 --- a/src/analyses/libraryFunctions.ml +++ b/src/analyses/libraryFunctions.ml @@ -389,6 +389,9 @@ let posix_descs_list: (string * LibraryDesc.t) list = LibraryDsl.[ ("alphasort", unknown [drop "a" [r]; drop "b" [r]]); ("gmtime_r", unknown [drop "timer" [r]; drop "result" [w]]); ("rand_r", special [drop "seedp" [r; w]] Rand); + ("srandom", unknown [drop "seed" []]); + ("random", special [] Rand); + ("posix_memalign", unknown [drop "memptr" [w]; drop "alignment" []; drop "size" []]); (* TODO: Malloc *) ] (** Pthread functions. *) From b96c010fb5c86b5b238b91668feeb0156f2cba8c Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Tue, 10 Oct 2023 17:36:58 +0300 Subject: [PATCH 093/140] Fix memOutOfBounds indentation --- src/analyses/memOutOfBounds.ml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/analyses/memOutOfBounds.ml b/src/analyses/memOutOfBounds.ml index 7015e6f143..c715a1d2e7 100644 --- a/src/analyses/memOutOfBounds.ml +++ b/src/analyses/memOutOfBounds.ml @@ -397,8 +397,7 @@ struct match desc.special arglist with | Memset { dest; ch; count; } -> check_count ctx f.vname dest count; | Memcpy { dest; src; n = count; } -> check_count ctx f.vname dest count; - | _ -> (); - ctx.local + | _ -> ctx.local let enter ctx (lval: lval option) (f:fundec) (args:exp list) : (D.t * D.t) list = List.iter (fun arg -> check_exp_for_oob_access ctx arg) args; From 5cc481148d4e079327e6f395c02e28e99cdaa414 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Tue, 10 Oct 2023 17:47:36 +0300 Subject: [PATCH 094/140] Fix library function duplicate check indentation (PR #1213) --- src/analyses/libraryFunctions.ml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/analyses/libraryFunctions.ml b/src/analyses/libraryFunctions.ml index dd9360d7b7..0f9c34f957 100644 --- a/src/analyses/libraryFunctions.ml +++ b/src/analyses/libraryFunctions.ml @@ -1047,11 +1047,11 @@ let all_library_descs: (string, LibraryDesc.t) Hashtbl.t = let activated_library_descs: (string, LibraryDesc.t) Hashtbl.t ResettableLazy.t = let union = Hashtbl.merge (fun _ desc1 desc2 -> - match desc1, desc2 with - | (Some _ as desc), None - | None, (Some _ as desc) -> desc - | _, _ -> assert false - ) + match desc1, desc2 with + | (Some _ as desc), None + | None, (Some _ as desc) -> desc + | _, _ -> assert false + ) in ResettableLazy.from_fun (fun () -> GobConfig.get_string_list "lib.activated" From e98911df182e6725bed56113613e30e7cd9f7fa1 Mon Sep 17 00:00:00 2001 From: Stanimir Bozhilov Date: Wed, 11 Oct 2023 11:53:06 +0300 Subject: [PATCH 095/140] Remove unnecessary pin Co-authored-by: Simmo Saan --- goblint.opam.locked | 3 --- 1 file changed, 3 deletions(-) diff --git a/goblint.opam.locked b/goblint.opam.locked index d5af6ea348..2744d2fe92 100644 --- a/goblint.opam.locked +++ b/goblint.opam.locked @@ -122,9 +122,6 @@ build: [ ] dev-repo: "git+https://github.com/goblint/analyzer.git" available: os-distribution != "alpine" & arch != "arm64" -pin-depends: [ - [ "goblint-cil.2.0.2" "git+https://github.com/goblint/cil.git#c7ffc37ad83216a84d90fdbf427cc02a68ea5331" ] -] conflicts: [ "result" {< "1.5"} ] From 072f99d701ddf09a97c9a7ab0b754be4c63ee138 Mon Sep 17 00:00:00 2001 From: Stanimir Bozhilov Date: Wed, 11 Oct 2023 10:57:37 +0200 Subject: [PATCH 096/140] Remove commented out code from `enter` in UAF analysis Add TODOs for future improvement there --- src/analyses/useAfterFree.ml | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/src/analyses/useAfterFree.ml b/src/analyses/useAfterFree.ml index 521f17d97f..ef63ab3e91 100644 --- a/src/analyses/useAfterFree.ml +++ b/src/analyses/useAfterFree.ml @@ -182,18 +182,10 @@ struct let enter ctx (lval:lval option) (f:fundec) (args:exp list) : (D.t * D.t) list = let caller_state = ctx.local in List.iter (fun arg -> warn_exp_might_contain_freed "enter" ctx arg) args; + (* TODO: The 2nd component of the callee state needs to contain only the heap vars from the caller state which are reachable from: *) + (* * Global program variables *) + (* * The callee arguments *) [caller_state, (AllocaVars.empty (), snd caller_state)] - (* if AllocaVars.is_empty (fst caller_state) && HeapVars.is_empty (snd caller_state) then - [caller_state, caller_state] - else ( - let reachable_from_args = List.fold_left (fun ad arg -> Queries.AD.join ad (ctx.ask (ReachableFrom arg))) (Queries.AD.empty ()) args in - if Queries.AD.is_top reachable_from_args || D.is_top caller_state then - [caller_state, caller_state] - else - let reachable_vars = Queries.AD.to_var_may reachable_from_args in - let callee_state = (AllocaVars.empty (), HeapVars.filter (fun var -> List.mem var reachable_vars) (snd caller_state)) in (* TODO: use AD.mem directly *) - [caller_state, callee_state] - ) *) let combine_env ctx (lval:lval option) fexp (f:fundec) (args:exp list) fc (callee_local:D.t) (f_ask:Queries.ask) : D.t = let (caller_stack_state, caller_heap_state) = ctx.local in From e339ed17c88a154785a0d70ab4ad1c1c0aa31730 Mon Sep 17 00:00:00 2001 From: Stanimir Bozhilov Date: Wed, 11 Oct 2023 11:59:50 +0300 Subject: [PATCH 097/140] Remove unnecessary stuff from test case `74/15` Co-authored-by: Simmo Saan --- tests/regression/74-use_after_free/15-juliet-uaf-global-var.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/tests/regression/74-use_after_free/15-juliet-uaf-global-var.c b/tests/regression/74-use_after_free/15-juliet-uaf-global-var.c index 9cb3b2b29a..cc9819950f 100644 --- a/tests/regression/74-use_after_free/15-juliet-uaf-global-var.c +++ b/tests/regression/74-use_after_free/15-juliet-uaf-global-var.c @@ -1,7 +1,5 @@ -//PARAM: --set ana.activated[+] useAfterFree --set ana.activated[+] threadJoins +//PARAM: --set ana.activated[+] useAfterFree #include -#include -#include int *global; From f018ea37bc1e2cfb66237283b44a8400fc5cf161 Mon Sep 17 00:00:00 2001 From: Michael Schwarz Date: Wed, 11 Oct 2023 11:36:01 +0200 Subject: [PATCH 098/140] Reduce duplication --- src/analyses/memOutOfBounds.ml | 45 ++++++++++++++-------------------- 1 file changed, 18 insertions(+), 27 deletions(-) diff --git a/src/analyses/memOutOfBounds.ml b/src/analyses/memOutOfBounds.ml index 68dae1d89a..d52bb1109a 100644 --- a/src/analyses/memOutOfBounds.ml +++ b/src/analyses/memOutOfBounds.ml @@ -165,32 +165,23 @@ struct with IntDomain.ArithmeticOnIntegerBot _ -> ID.bot_of @@ Cilfacade.ptrdiff_ikind () end - let rec cil_offs_to_idx ctx typ offs = - match offs with - | NoOffset -> intdom_of_int 0 - | Field (field, o) -> - let field_as_offset = Field (field, NoOffset) in - let bits_offset, _size = GoblintCil.bitsOffset (TComp (field.fcomp, [])) field_as_offset in - let bytes_offset = intdom_of_int (bits_offset / 8) in - let remaining_offset = cil_offs_to_idx ctx field.ftype o in - begin - try ID.add bytes_offset remaining_offset - with IntDomain.ArithmeticOnIntegerBot _ -> ID.bot_of @@ Cilfacade.ptrdiff_ikind () - end - | Index (x, o) -> - begin try - begin match ctx.ask (Queries.EvalInt x) with - | `Top -> ID.top_of @@ Cilfacade.ptrdiff_ikind () - | `Bot -> ID.bot_of @@ Cilfacade.ptrdiff_ikind () - | `Lifted eval_x -> - let typ_size_in_bytes = size_of_type_in_bytes typ in - let casted_eval_x = ID.cast_to (Cilfacade.ptrdiff_ikind ()) eval_x in - let bytes_offset = ID.mul typ_size_in_bytes casted_eval_x in - let remaining_offset = cil_offs_to_idx ctx typ o in - ID.add bytes_offset remaining_offset - end - with IntDomain.ArithmeticOnIntegerBot _ -> ID.bot_of @@ Cilfacade.ptrdiff_ikind () - end + let cil_offs_to_idx ctx typ offs = + (* TODO: Some duplication with convert_offset in base.ml, unclear how to immediately get more reuse *) + let rec convert_offset (ofs: offset) = + match ofs with + | NoOffset -> `NoOffset + | Field (fld, ofs) -> `Field (fld, convert_offset ofs) + | Index (exp, ofs) when CilType.Exp.equal exp Offset.Index.Exp.any -> (* special offset added by convertToQueryLval *) + `Index (ID.top (), convert_offset ofs) + | Index (exp, ofs) -> + let i = match ctx.ask (Queries.EvalInt exp) with + | `Lifted x -> x + | _ -> ID.top_of @@ Cilfacade.ptrdiff_ikind () + in + `Index (i, convert_offset ofs) + in + PreValueDomain.Offs.to_index (convert_offset offs) + let check_unknown_addr_deref ctx ptr = let may_contain_unknown_addr = @@ -517,4 +508,4 @@ struct end let _ = - MCP.register_analysis (module Spec : MCPSpec) \ No newline at end of file + MCP.register_analysis (module Spec : MCPSpec) From 7ddd47167395781152fe85efa66f57ca74caa477 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 11 Oct 2023 14:12:21 +0300 Subject: [PATCH 099/140] Improve MCP.D pretty --- src/analyses/mCPRegistry.ml | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/src/analyses/mCPRegistry.ml b/src/analyses/mCPRegistry.ml index d1311e0427..8560e5122d 100644 --- a/src/analyses/mCPRegistry.ml +++ b/src/analyses/mCPRegistry.ml @@ -149,20 +149,21 @@ struct let unop_map f x = List.rev @@ unop_fold (fun a n s d -> (n, f s d) :: a) [] x - let pretty () x = - let f a n (module S : Printable.S) x = Pretty.dprintf "%s:%a" (S.name ()) S.pretty (obj x) :: a in - let xs = unop_fold f [] x in - match xs with - | [] -> text "[]" - | x :: [] -> x - | x :: y -> - let rest = List.fold_left (fun p n->p ++ text "," ++ break ++ n) nil y in - text "[" ++ align ++ x ++ rest ++ unalign ++ text "]" + let pretty () xs = + let pretty_one a n (module S: Printable.S) x = + let doc = Pretty.dprintf "%s:%a" (find_spec_name n) S.pretty (obj x) in + match a with + | None -> Some doc + | Some a -> Some (a ++ text "," ++ line ++ doc) + in + let doc = Option.default Pretty.nil (unop_fold pretty_one None xs) in + Pretty.dprintf "[@[%a@]]" Pretty.insert doc let show x = let xs = unop_fold (fun a n (module S : Printable.S) x -> let analysis_name = find_spec_name n in - (analysis_name ^ ":(" ^ S.show (obj x) ^ ")") :: a) [] x + (analysis_name ^ ":(" ^ S.show (obj x) ^ ")") :: a + ) [] x in IO.to_string (List.print ~first:"[" ~last:"]" ~sep:", " String.print) (rev xs) From e2a585999e3f46642f4474aa339cd6567e429448 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 11 Oct 2023 14:12:45 +0300 Subject: [PATCH 100/140] Improve MCP.D pretty_diff --- src/analyses/mCPRegistry.ml | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/src/analyses/mCPRegistry.ml b/src/analyses/mCPRegistry.ml index 8560e5122d..32847bb3ed 100644 --- a/src/analyses/mCPRegistry.ml +++ b/src/analyses/mCPRegistry.ml @@ -370,12 +370,19 @@ struct let top () = map (fun (n,(module S : Lattice.S)) -> (n,repr @@ S.top ())) @@ domain_list () let bot () = map (fun (n,(module S : Lattice.S)) -> (n,repr @@ S.bot ())) @@ domain_list () - let pretty_diff () (x,y) = - let f a n (module S : Lattice.S) x y = - if S.leq (obj x) (obj y) then a - else a ++ S.pretty_diff () (obj x, obj y) ++ text ". " + let pretty_diff () (xs, ys) = + let pretty_one a n (module S: Lattice.S) x y = + if S.leq (obj x) (obj y) then + a + else ( + let doc = Pretty.dprintf "%s:%a" (find_spec_name n) S.pretty_diff (obj x, obj y) in + match a with + | None -> Some doc + | Some a -> Some (a ++ text "," ++ line ++ doc) + ) in - binop_fold f nil x y + let doc = Option.default Pretty.nil (binop_fold pretty_one None xs ys) in + Pretty.dprintf "[@[%a@]]" Pretty.insert doc end module DomVariantLattice0 (DLSpec : DomainListLatticeSpec) From 44f775942ce6d82736fe2150ff7af219dc0c1532 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 11 Oct 2023 14:35:44 +0300 Subject: [PATCH 101/140] Improve empty MapDomain pretty --- src/domains/mapDomain.ml | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/domains/mapDomain.ml b/src/domains/mapDomain.ml index 6c40ab9792..76dec6f0d2 100644 --- a/src/domains/mapDomain.ml +++ b/src/domains/mapDomain.ml @@ -68,11 +68,14 @@ end module Print (D: Printable.S) (R: Printable.S) (M: Bindings with type key = D.t and type value = R.t) = struct let pretty () map = - let pretty_bindings () = M.fold (fun k v acc -> - acc ++ dprintf "%a ->@? @[%a@]\n" D.pretty k R.pretty v + let doc = M.fold (fun k v acc -> + acc ++ dprintf "%a ->@?@[%a@]\n" D.pretty k R.pretty v ) map nil in - dprintf "@[{\n @[%t@]}@]" pretty_bindings + if doc = Pretty.nil then + text "{}" + else + dprintf "@[{\n @[%a@]}@]" Pretty.insert doc let show map = GobPretty.sprint pretty map From 00b7e623a7a2ddaa36a91cfd21546de33008e10e Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 11 Oct 2023 15:00:49 +0300 Subject: [PATCH 102/140] Add module names to Prod and Prod3 --- src/domains/printable.ml | 32 ++++++++++++++++++++++++++------ 1 file changed, 26 insertions(+), 6 deletions(-) diff --git a/src/domains/printable.ml b/src/domains/printable.ml index 1207d35db2..b0755fb730 100644 --- a/src/domains/printable.ml +++ b/src/domains/printable.ml @@ -366,9 +366,17 @@ struct let pretty () (x,y) = if expand_fst || expand_snd then text "(" + ++ text (Base1.name ()) + ++ text ":" + ++ align ++ (if expand_fst then Base1.pretty () x else text (Base1.show x)) + ++ unalign ++ text ", " + ++ text (Base2.name ()) + ++ text ":" + ++ align ++ (if expand_snd then Base2.pretty () y else text (Base2.show y)) + ++ unalign ++ text ")" else text (show (x,y)) @@ -403,12 +411,24 @@ struct "(" ^ !first ^ ", " ^ !second ^ ", " ^ !third ^ ")" let pretty () (x,y,z) = - text "(" ++ - Base1.pretty () x - ++ text ", " ++ - Base2.pretty () y - ++ text ", " ++ - Base3.pretty () z + text "(" + ++ text (Base1.name ()) + ++ text ":" + ++ align + ++ Base1.pretty () x + ++ unalign + ++ text ", " + ++ text (Base2.name ()) + ++ text ":" + ++ align + ++ Base2.pretty () y + ++ unalign + ++ text ", " + ++ text (Base3.name ()) + ++ text ":" + ++ align + ++ Base3.pretty () z + ++ unalign ++ text ")" let printXml f (x,y,z) = From 83fef2cd47fb15d937192392684c4e39d9d136bb Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 11 Oct 2023 15:01:03 +0300 Subject: [PATCH 103/140] Add names to mutex analysis domains --- src/analyses/mutexAnalysis.ml | 2 ++ src/cdomains/lockDomain.ml | 1 + 2 files changed, 3 insertions(+) diff --git a/src/analyses/mutexAnalysis.ml b/src/analyses/mutexAnalysis.ml index 5a61976ef5..ee050f55ca 100644 --- a/src/analyses/mutexAnalysis.ml +++ b/src/analyses/mutexAnalysis.ml @@ -30,6 +30,8 @@ struct include MapDomain.MapTop_LiftBot (ValueDomain.Addr) (Count) + let name () = "multiplicity" + let increment v x = let current = find v x in if current = max_count () then diff --git a/src/cdomains/lockDomain.ml b/src/cdomains/lockDomain.ml index 4bc97b34ab..107c1c0692 100644 --- a/src/cdomains/lockDomain.ml +++ b/src/cdomains/lockDomain.ml @@ -37,6 +37,7 @@ struct end include SetDomain.Reverse(SetDomain.ToppedSet (Lock) (struct let topname = "All mutexes" end)) + let name () = "lockset" let may_be_same_offset of1 of2 = (* Only reached with definite of2 and indefinite of1. *) From 151ccb15068bb262a0134ec818fe7ad307615379 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 11 Oct 2023 15:01:17 +0300 Subject: [PATCH 104/140] Add names to mallocWrapper analysis domains --- src/analyses/wrapperFunctionAnalysis.ml | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/analyses/wrapperFunctionAnalysis.ml b/src/analyses/wrapperFunctionAnalysis.ml index 5c0176df48..e98597a66a 100644 --- a/src/analyses/wrapperFunctionAnalysis.ml +++ b/src/analyses/wrapperFunctionAnalysis.ml @@ -33,11 +33,20 @@ struct Introduce a function for this to keep things consistent. *) let node_for_ctx ctx = ctx.prev_node + module NodeFlatLattice = + struct + include NodeFlatLattice + let name () = "wrapper call" + end + module UniqueCount = UniqueCount (* Map for counting function call node visits up to n (of the current thread). *) module UniqueCallCounter = - MapDomain.MapBot_LiftTop(NodeFlatLattice)(UniqueCount) + struct + include MapDomain.MapBot_LiftTop(NodeFlatLattice)(UniqueCount) + let name () = "unique calls" + end (* Increase counter for given node. If it does not exist yet, create it. *) let add_unique_call counter node = From b0ce3691ec8525711f57889ddb29b44670090d76 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 11 Oct 2023 15:01:24 +0300 Subject: [PATCH 105/140] Add names to threadid analysis domains --- src/analyses/threadId.ml | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/src/analyses/threadId.ml b/src/analyses/threadId.ml index 4acf88a7ef..8144aea507 100644 --- a/src/analyses/threadId.ml +++ b/src/analyses/threadId.ml @@ -29,11 +29,30 @@ module Spec = struct include Analyses.IdentitySpec - module N = Lattice.Flat (VNI) (struct let bot_name = "unknown node" let top_name = "unknown node" end) + module N = + struct + include Lattice.Flat (VNI) (struct let bot_name = "unknown node" let top_name = "unknown node" end) + let name () = "wrapper call" + end module TD = Thread.D + module Created = + struct + module Current = + struct + include TD + let name () = "current function" + end + module Callees = + struct + include TD + let name () = "callees" + end + include Lattice.Prod (Current) (Callees) + let name () = "created" + end (** Uniqueness Counter * TID * (All thread creates of current thread * All thread creates of the current function and its callees) *) - module D = Lattice.Prod3 (N) (ThreadLifted) (Lattice.Prod(TD)(TD)) + module D = Lattice.Prod3 (N) (ThreadLifted) (Created) module C = D module P = IdentityP (D) From 0f70e17d5d13404b83d1caed8b4219471c32776f Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 11 Oct 2023 15:09:09 +0300 Subject: [PATCH 106/140] Fix MCP module names --- src/analyses/mCPRegistry.ml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/analyses/mCPRegistry.ml b/src/analyses/mCPRegistry.ml index 32847bb3ed..810da827ff 100644 --- a/src/analyses/mCPRegistry.ml +++ b/src/analyses/mCPRegistry.ml @@ -318,6 +318,7 @@ struct open Obj include DomListPrintable (PrintableOfRepresentativeSpec (DLSpec)) + let name () = "MCP.P" type elt = (int * unknown) list @@ -344,6 +345,7 @@ struct open Obj include DomListPrintable (PrintableOfLatticeSpec (DLSpec)) + let name () = "MCP.D" let binop_fold f a (x:t) (y:t) = GobList.fold_left3 (fun a (n,d) (n',d') (n'',s) -> assert (n = n' && n = n''); f a n s d d') a x y (domain_list ()) From d9afd55a63514ff47f163c34ff07a41ffd48a30c Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 11 Oct 2023 15:09:17 +0300 Subject: [PATCH 107/140] Add names to region analysis domains --- src/cdomains/regionDomain.ml | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/cdomains/regionDomain.ml b/src/cdomains/regionDomain.ml index 143ba086a6..b577e3499f 100644 --- a/src/cdomains/regionDomain.ml +++ b/src/cdomains/regionDomain.ml @@ -9,6 +9,15 @@ module B = Printable.UnitConf (struct let name = "•" end) module VFB = struct include Printable.Either (VF) (B) + let name () = "region" + + let pretty () = function + | `Right () -> Pretty.text "•" + | `Left x -> VF.pretty () x + + let show = function + | `Right () -> "•" + | `Left x -> VF.show x let printXml f = function | `Right () -> @@ -51,6 +60,7 @@ end module RS = struct include PartitionDomain.Set (VFB) + let name () = "regions" let single_vf vf = singleton (VFB.of_vf vf) let single_bullet = singleton (VFB.bullet) let remove_bullet x = remove VFB.bullet x From a2f36fb4179705a812cc3b0f589d5fd0c9649dc9 Mon Sep 17 00:00:00 2001 From: Stanimir Bozhilov Date: Wed, 11 Oct 2023 16:46:33 +0200 Subject: [PATCH 108/140] Reorganize memsafety regr. tests --- .../{77-mem-oob => 74-invalid_deref}/01-oob-heap-simple.c | 0 .../{74-use_after_free => 74-invalid_deref}/02-conditional-uaf.c | 0 .../{74-use_after_free => 74-invalid_deref}/03-nested-ptr-uaf.c | 0 .../04-function-call-uaf.c | 0 .../{77-mem-oob => 74-invalid_deref}/05-oob-implicit-deref.c | 0 tests/regression/{77-mem-oob => 74-invalid_deref}/06-memset-oob.c | 0 tests/regression/{77-mem-oob => 74-invalid_deref}/07-memcpy-oob.c | 0 .../{77-mem-oob => 74-invalid_deref}/08-memset-memcpy-array.c | 0 .../{74-use_after_free => 74-invalid_deref}/09-juliet-uaf.c | 0 .../{77-mem-oob => 74-invalid_deref}/10-oob-two-loops.c | 0 .../{77-mem-oob => 74-invalid_deref}/11-address-offset-oob.c | 0 .../{77-mem-oob => 74-invalid_deref}/12-memcpy-oob-src.c | 0 .../{77-mem-oob => 74-invalid_deref}/13-mem-oob-packed-struct.c | 0 .../{74-use_after_free => 74-invalid_deref}/14-alloca-uaf.c | 0 .../15-juliet-uaf-global-var.c | 0 .../16-uaf-packed-struct.c | 0 .../17-scopes-no-static.c} | 0 .../01-simple-uaf.c => 74-invalid_deref/18-simple-uaf.c} | 0 .../19-oob-stack-simple.c} | 0 .../20-scopes-global-var.c} | 0 .../{77-mem-oob/03-oob-loop.c => 74-invalid_deref/21-oob-loop.c} | 0 .../03-scopes-static.c => 74-invalid_deref/22-scopes-static.c} | 0 .../23-oob-deref-after-ptr-arith.c} | 0 .../24-uaf-free-in-wrapper-fun.c} | 0 .../06-uaf-struct.c => 74-invalid_deref/25-uaf-struct.c} | 0 .../26-memset-memcpy-addr-offs.c} | 0 .../27-wrapper-funs-uaf.c} | 0 .../28-multi-threaded-uaf.c} | 0 .../29-multi-threaded-uaf-with-joined-thread.c} | 0 .../01-invalid-dealloc-simple.c | 0 .../02-invalid-dealloc-struct.c | 0 .../03-invalid-dealloc-array.c | 0 .../{75-invalid_dealloc => 75-invalid_free}/04-invalid-realloc.c | 0 .../{75-invalid_dealloc => 75-invalid_free}/05-free-at-offset.c | 0 .../06-realloc-at-offset.c | 0 .../07-free-at-struct-offset.c | 0 .../08-itc-no-double-free.c | 0 .../09-juliet-invalid-dealloc-alloca.c | 0 .../10-invalid-dealloc-union.c | 0 .../07-itc-double-free.c => 75-invalid_free/11-itc-double-free.c} | 0 .../12-realloc-at-struct-offset.c} | 0 .../13-juliet-double-free.c} | 0 42 files changed, 0 insertions(+), 0 deletions(-) rename tests/regression/{77-mem-oob => 74-invalid_deref}/01-oob-heap-simple.c (100%) rename tests/regression/{74-use_after_free => 74-invalid_deref}/02-conditional-uaf.c (100%) rename tests/regression/{74-use_after_free => 74-invalid_deref}/03-nested-ptr-uaf.c (100%) rename tests/regression/{74-use_after_free => 74-invalid_deref}/04-function-call-uaf.c (100%) rename tests/regression/{77-mem-oob => 74-invalid_deref}/05-oob-implicit-deref.c (100%) rename tests/regression/{77-mem-oob => 74-invalid_deref}/06-memset-oob.c (100%) rename tests/regression/{77-mem-oob => 74-invalid_deref}/07-memcpy-oob.c (100%) rename tests/regression/{77-mem-oob => 74-invalid_deref}/08-memset-memcpy-array.c (100%) rename tests/regression/{74-use_after_free => 74-invalid_deref}/09-juliet-uaf.c (100%) rename tests/regression/{77-mem-oob => 74-invalid_deref}/10-oob-two-loops.c (100%) rename tests/regression/{77-mem-oob => 74-invalid_deref}/11-address-offset-oob.c (100%) rename tests/regression/{77-mem-oob => 74-invalid_deref}/12-memcpy-oob-src.c (100%) rename tests/regression/{77-mem-oob => 74-invalid_deref}/13-mem-oob-packed-struct.c (100%) rename tests/regression/{74-use_after_free => 74-invalid_deref}/14-alloca-uaf.c (100%) rename tests/regression/{74-use_after_free => 74-invalid_deref}/15-juliet-uaf-global-var.c (100%) rename tests/regression/{74-use_after_free => 74-invalid_deref}/16-uaf-packed-struct.c (100%) rename tests/regression/{78-invalid-deref-scopes/01-scopes-no-static.c => 74-invalid_deref/17-scopes-no-static.c} (100%) rename tests/regression/{74-use_after_free/01-simple-uaf.c => 74-invalid_deref/18-simple-uaf.c} (100%) rename tests/regression/{77-mem-oob/02-oob-stack-simple.c => 74-invalid_deref/19-oob-stack-simple.c} (100%) rename tests/regression/{78-invalid-deref-scopes/02-scopes-global-var.c => 74-invalid_deref/20-scopes-global-var.c} (100%) rename tests/regression/{77-mem-oob/03-oob-loop.c => 74-invalid_deref/21-oob-loop.c} (100%) rename tests/regression/{78-invalid-deref-scopes/03-scopes-static.c => 74-invalid_deref/22-scopes-static.c} (100%) rename tests/regression/{77-mem-oob/04-oob-deref-after-ptr-arith.c => 74-invalid_deref/23-oob-deref-after-ptr-arith.c} (100%) rename tests/regression/{74-use_after_free/05-uaf-free-in-wrapper-fun.c => 74-invalid_deref/24-uaf-free-in-wrapper-fun.c} (100%) rename tests/regression/{74-use_after_free/06-uaf-struct.c => 74-invalid_deref/25-uaf-struct.c} (100%) rename tests/regression/{77-mem-oob/09-memset-memcpy-addr-offs.c => 74-invalid_deref/26-memset-memcpy-addr-offs.c} (100%) rename tests/regression/{74-use_after_free/11-wrapper-funs-uaf.c => 74-invalid_deref/27-wrapper-funs-uaf.c} (100%) rename tests/regression/{74-use_after_free/12-multi-threaded-uaf.c => 74-invalid_deref/28-multi-threaded-uaf.c} (100%) rename tests/regression/{74-use_after_free/13-multi-threaded-uaf-with-joined-thread.c => 74-invalid_deref/29-multi-threaded-uaf-with-joined-thread.c} (100%) rename tests/regression/{75-invalid_dealloc => 75-invalid_free}/01-invalid-dealloc-simple.c (100%) rename tests/regression/{75-invalid_dealloc => 75-invalid_free}/02-invalid-dealloc-struct.c (100%) rename tests/regression/{75-invalid_dealloc => 75-invalid_free}/03-invalid-dealloc-array.c (100%) rename tests/regression/{75-invalid_dealloc => 75-invalid_free}/04-invalid-realloc.c (100%) rename tests/regression/{75-invalid_dealloc => 75-invalid_free}/05-free-at-offset.c (100%) rename tests/regression/{75-invalid_dealloc => 75-invalid_free}/06-realloc-at-offset.c (100%) rename tests/regression/{75-invalid_dealloc => 75-invalid_free}/07-free-at-struct-offset.c (100%) rename tests/regression/{74-use_after_free => 75-invalid_free}/08-itc-no-double-free.c (100%) rename tests/regression/{75-invalid_dealloc => 75-invalid_free}/09-juliet-invalid-dealloc-alloca.c (100%) rename tests/regression/{75-invalid_dealloc => 75-invalid_free}/10-invalid-dealloc-union.c (100%) rename tests/regression/{74-use_after_free/07-itc-double-free.c => 75-invalid_free/11-itc-double-free.c} (100%) rename tests/regression/{75-invalid_dealloc/08-realloc-at-struct-offset.c => 75-invalid_free/12-realloc-at-struct-offset.c} (100%) rename tests/regression/{74-use_after_free/10-juliet-double-free.c => 75-invalid_free/13-juliet-double-free.c} (100%) diff --git a/tests/regression/77-mem-oob/01-oob-heap-simple.c b/tests/regression/74-invalid_deref/01-oob-heap-simple.c similarity index 100% rename from tests/regression/77-mem-oob/01-oob-heap-simple.c rename to tests/regression/74-invalid_deref/01-oob-heap-simple.c diff --git a/tests/regression/74-use_after_free/02-conditional-uaf.c b/tests/regression/74-invalid_deref/02-conditional-uaf.c similarity index 100% rename from tests/regression/74-use_after_free/02-conditional-uaf.c rename to tests/regression/74-invalid_deref/02-conditional-uaf.c diff --git a/tests/regression/74-use_after_free/03-nested-ptr-uaf.c b/tests/regression/74-invalid_deref/03-nested-ptr-uaf.c similarity index 100% rename from tests/regression/74-use_after_free/03-nested-ptr-uaf.c rename to tests/regression/74-invalid_deref/03-nested-ptr-uaf.c diff --git a/tests/regression/74-use_after_free/04-function-call-uaf.c b/tests/regression/74-invalid_deref/04-function-call-uaf.c similarity index 100% rename from tests/regression/74-use_after_free/04-function-call-uaf.c rename to tests/regression/74-invalid_deref/04-function-call-uaf.c diff --git a/tests/regression/77-mem-oob/05-oob-implicit-deref.c b/tests/regression/74-invalid_deref/05-oob-implicit-deref.c similarity index 100% rename from tests/regression/77-mem-oob/05-oob-implicit-deref.c rename to tests/regression/74-invalid_deref/05-oob-implicit-deref.c diff --git a/tests/regression/77-mem-oob/06-memset-oob.c b/tests/regression/74-invalid_deref/06-memset-oob.c similarity index 100% rename from tests/regression/77-mem-oob/06-memset-oob.c rename to tests/regression/74-invalid_deref/06-memset-oob.c diff --git a/tests/regression/77-mem-oob/07-memcpy-oob.c b/tests/regression/74-invalid_deref/07-memcpy-oob.c similarity index 100% rename from tests/regression/77-mem-oob/07-memcpy-oob.c rename to tests/regression/74-invalid_deref/07-memcpy-oob.c diff --git a/tests/regression/77-mem-oob/08-memset-memcpy-array.c b/tests/regression/74-invalid_deref/08-memset-memcpy-array.c similarity index 100% rename from tests/regression/77-mem-oob/08-memset-memcpy-array.c rename to tests/regression/74-invalid_deref/08-memset-memcpy-array.c diff --git a/tests/regression/74-use_after_free/09-juliet-uaf.c b/tests/regression/74-invalid_deref/09-juliet-uaf.c similarity index 100% rename from tests/regression/74-use_after_free/09-juliet-uaf.c rename to tests/regression/74-invalid_deref/09-juliet-uaf.c diff --git a/tests/regression/77-mem-oob/10-oob-two-loops.c b/tests/regression/74-invalid_deref/10-oob-two-loops.c similarity index 100% rename from tests/regression/77-mem-oob/10-oob-two-loops.c rename to tests/regression/74-invalid_deref/10-oob-two-loops.c diff --git a/tests/regression/77-mem-oob/11-address-offset-oob.c b/tests/regression/74-invalid_deref/11-address-offset-oob.c similarity index 100% rename from tests/regression/77-mem-oob/11-address-offset-oob.c rename to tests/regression/74-invalid_deref/11-address-offset-oob.c diff --git a/tests/regression/77-mem-oob/12-memcpy-oob-src.c b/tests/regression/74-invalid_deref/12-memcpy-oob-src.c similarity index 100% rename from tests/regression/77-mem-oob/12-memcpy-oob-src.c rename to tests/regression/74-invalid_deref/12-memcpy-oob-src.c diff --git a/tests/regression/77-mem-oob/13-mem-oob-packed-struct.c b/tests/regression/74-invalid_deref/13-mem-oob-packed-struct.c similarity index 100% rename from tests/regression/77-mem-oob/13-mem-oob-packed-struct.c rename to tests/regression/74-invalid_deref/13-mem-oob-packed-struct.c diff --git a/tests/regression/74-use_after_free/14-alloca-uaf.c b/tests/regression/74-invalid_deref/14-alloca-uaf.c similarity index 100% rename from tests/regression/74-use_after_free/14-alloca-uaf.c rename to tests/regression/74-invalid_deref/14-alloca-uaf.c diff --git a/tests/regression/74-use_after_free/15-juliet-uaf-global-var.c b/tests/regression/74-invalid_deref/15-juliet-uaf-global-var.c similarity index 100% rename from tests/regression/74-use_after_free/15-juliet-uaf-global-var.c rename to tests/regression/74-invalid_deref/15-juliet-uaf-global-var.c diff --git a/tests/regression/74-use_after_free/16-uaf-packed-struct.c b/tests/regression/74-invalid_deref/16-uaf-packed-struct.c similarity index 100% rename from tests/regression/74-use_after_free/16-uaf-packed-struct.c rename to tests/regression/74-invalid_deref/16-uaf-packed-struct.c diff --git a/tests/regression/78-invalid-deref-scopes/01-scopes-no-static.c b/tests/regression/74-invalid_deref/17-scopes-no-static.c similarity index 100% rename from tests/regression/78-invalid-deref-scopes/01-scopes-no-static.c rename to tests/regression/74-invalid_deref/17-scopes-no-static.c diff --git a/tests/regression/74-use_after_free/01-simple-uaf.c b/tests/regression/74-invalid_deref/18-simple-uaf.c similarity index 100% rename from tests/regression/74-use_after_free/01-simple-uaf.c rename to tests/regression/74-invalid_deref/18-simple-uaf.c diff --git a/tests/regression/77-mem-oob/02-oob-stack-simple.c b/tests/regression/74-invalid_deref/19-oob-stack-simple.c similarity index 100% rename from tests/regression/77-mem-oob/02-oob-stack-simple.c rename to tests/regression/74-invalid_deref/19-oob-stack-simple.c diff --git a/tests/regression/78-invalid-deref-scopes/02-scopes-global-var.c b/tests/regression/74-invalid_deref/20-scopes-global-var.c similarity index 100% rename from tests/regression/78-invalid-deref-scopes/02-scopes-global-var.c rename to tests/regression/74-invalid_deref/20-scopes-global-var.c diff --git a/tests/regression/77-mem-oob/03-oob-loop.c b/tests/regression/74-invalid_deref/21-oob-loop.c similarity index 100% rename from tests/regression/77-mem-oob/03-oob-loop.c rename to tests/regression/74-invalid_deref/21-oob-loop.c diff --git a/tests/regression/78-invalid-deref-scopes/03-scopes-static.c b/tests/regression/74-invalid_deref/22-scopes-static.c similarity index 100% rename from tests/regression/78-invalid-deref-scopes/03-scopes-static.c rename to tests/regression/74-invalid_deref/22-scopes-static.c diff --git a/tests/regression/77-mem-oob/04-oob-deref-after-ptr-arith.c b/tests/regression/74-invalid_deref/23-oob-deref-after-ptr-arith.c similarity index 100% rename from tests/regression/77-mem-oob/04-oob-deref-after-ptr-arith.c rename to tests/regression/74-invalid_deref/23-oob-deref-after-ptr-arith.c diff --git a/tests/regression/74-use_after_free/05-uaf-free-in-wrapper-fun.c b/tests/regression/74-invalid_deref/24-uaf-free-in-wrapper-fun.c similarity index 100% rename from tests/regression/74-use_after_free/05-uaf-free-in-wrapper-fun.c rename to tests/regression/74-invalid_deref/24-uaf-free-in-wrapper-fun.c diff --git a/tests/regression/74-use_after_free/06-uaf-struct.c b/tests/regression/74-invalid_deref/25-uaf-struct.c similarity index 100% rename from tests/regression/74-use_after_free/06-uaf-struct.c rename to tests/regression/74-invalid_deref/25-uaf-struct.c diff --git a/tests/regression/77-mem-oob/09-memset-memcpy-addr-offs.c b/tests/regression/74-invalid_deref/26-memset-memcpy-addr-offs.c similarity index 100% rename from tests/regression/77-mem-oob/09-memset-memcpy-addr-offs.c rename to tests/regression/74-invalid_deref/26-memset-memcpy-addr-offs.c diff --git a/tests/regression/74-use_after_free/11-wrapper-funs-uaf.c b/tests/regression/74-invalid_deref/27-wrapper-funs-uaf.c similarity index 100% rename from tests/regression/74-use_after_free/11-wrapper-funs-uaf.c rename to tests/regression/74-invalid_deref/27-wrapper-funs-uaf.c diff --git a/tests/regression/74-use_after_free/12-multi-threaded-uaf.c b/tests/regression/74-invalid_deref/28-multi-threaded-uaf.c similarity index 100% rename from tests/regression/74-use_after_free/12-multi-threaded-uaf.c rename to tests/regression/74-invalid_deref/28-multi-threaded-uaf.c diff --git a/tests/regression/74-use_after_free/13-multi-threaded-uaf-with-joined-thread.c b/tests/regression/74-invalid_deref/29-multi-threaded-uaf-with-joined-thread.c similarity index 100% rename from tests/regression/74-use_after_free/13-multi-threaded-uaf-with-joined-thread.c rename to tests/regression/74-invalid_deref/29-multi-threaded-uaf-with-joined-thread.c diff --git a/tests/regression/75-invalid_dealloc/01-invalid-dealloc-simple.c b/tests/regression/75-invalid_free/01-invalid-dealloc-simple.c similarity index 100% rename from tests/regression/75-invalid_dealloc/01-invalid-dealloc-simple.c rename to tests/regression/75-invalid_free/01-invalid-dealloc-simple.c diff --git a/tests/regression/75-invalid_dealloc/02-invalid-dealloc-struct.c b/tests/regression/75-invalid_free/02-invalid-dealloc-struct.c similarity index 100% rename from tests/regression/75-invalid_dealloc/02-invalid-dealloc-struct.c rename to tests/regression/75-invalid_free/02-invalid-dealloc-struct.c diff --git a/tests/regression/75-invalid_dealloc/03-invalid-dealloc-array.c b/tests/regression/75-invalid_free/03-invalid-dealloc-array.c similarity index 100% rename from tests/regression/75-invalid_dealloc/03-invalid-dealloc-array.c rename to tests/regression/75-invalid_free/03-invalid-dealloc-array.c diff --git a/tests/regression/75-invalid_dealloc/04-invalid-realloc.c b/tests/regression/75-invalid_free/04-invalid-realloc.c similarity index 100% rename from tests/regression/75-invalid_dealloc/04-invalid-realloc.c rename to tests/regression/75-invalid_free/04-invalid-realloc.c diff --git a/tests/regression/75-invalid_dealloc/05-free-at-offset.c b/tests/regression/75-invalid_free/05-free-at-offset.c similarity index 100% rename from tests/regression/75-invalid_dealloc/05-free-at-offset.c rename to tests/regression/75-invalid_free/05-free-at-offset.c diff --git a/tests/regression/75-invalid_dealloc/06-realloc-at-offset.c b/tests/regression/75-invalid_free/06-realloc-at-offset.c similarity index 100% rename from tests/regression/75-invalid_dealloc/06-realloc-at-offset.c rename to tests/regression/75-invalid_free/06-realloc-at-offset.c diff --git a/tests/regression/75-invalid_dealloc/07-free-at-struct-offset.c b/tests/regression/75-invalid_free/07-free-at-struct-offset.c similarity index 100% rename from tests/regression/75-invalid_dealloc/07-free-at-struct-offset.c rename to tests/regression/75-invalid_free/07-free-at-struct-offset.c diff --git a/tests/regression/74-use_after_free/08-itc-no-double-free.c b/tests/regression/75-invalid_free/08-itc-no-double-free.c similarity index 100% rename from tests/regression/74-use_after_free/08-itc-no-double-free.c rename to tests/regression/75-invalid_free/08-itc-no-double-free.c diff --git a/tests/regression/75-invalid_dealloc/09-juliet-invalid-dealloc-alloca.c b/tests/regression/75-invalid_free/09-juliet-invalid-dealloc-alloca.c similarity index 100% rename from tests/regression/75-invalid_dealloc/09-juliet-invalid-dealloc-alloca.c rename to tests/regression/75-invalid_free/09-juliet-invalid-dealloc-alloca.c diff --git a/tests/regression/75-invalid_dealloc/10-invalid-dealloc-union.c b/tests/regression/75-invalid_free/10-invalid-dealloc-union.c similarity index 100% rename from tests/regression/75-invalid_dealloc/10-invalid-dealloc-union.c rename to tests/regression/75-invalid_free/10-invalid-dealloc-union.c diff --git a/tests/regression/74-use_after_free/07-itc-double-free.c b/tests/regression/75-invalid_free/11-itc-double-free.c similarity index 100% rename from tests/regression/74-use_after_free/07-itc-double-free.c rename to tests/regression/75-invalid_free/11-itc-double-free.c diff --git a/tests/regression/75-invalid_dealloc/08-realloc-at-struct-offset.c b/tests/regression/75-invalid_free/12-realloc-at-struct-offset.c similarity index 100% rename from tests/regression/75-invalid_dealloc/08-realloc-at-struct-offset.c rename to tests/regression/75-invalid_free/12-realloc-at-struct-offset.c diff --git a/tests/regression/74-use_after_free/10-juliet-double-free.c b/tests/regression/75-invalid_free/13-juliet-double-free.c similarity index 100% rename from tests/regression/74-use_after_free/10-juliet-double-free.c rename to tests/regression/75-invalid_free/13-juliet-double-free.c From 3281c74399a6f4b9c16a64ca11e041897ff36d9a Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 11 Oct 2023 17:54:59 +0300 Subject: [PATCH 109/140] Temporarily reintroduce old unqualified directory structure inside common library --- .github/workflows/options.yml | 6 +++--- .readthedocs.yaml | 2 +- docs/user-guide/configuring.md | 2 +- src/common/{ => cdomains}/basetype.ml | 0 src/common/{ => domains}/lattice.ml | 0 src/common/{ => domains}/myCheck.ml | 0 src/common/{ => domains}/printable.ml | 0 src/common/dune | 4 ++-- src/common/{ => framework}/analysisState.ml | 0 src/common/{ => framework}/controlSpecC.ml | 0 src/common/{ => framework}/controlSpecC.mli | 0 src/common/{ => framework}/edge.ml | 0 src/common/{ => framework}/myCFG.ml | 0 src/common/{ => framework}/node.ml | 0 src/common/{ => framework}/node0.ml | 0 src/common/{ => incremental}/updateCil0.ml | 0 src/common/{ => util}/afterConfig.ml | 0 src/common/{ => util}/cilType.ml | 0 src/common/{ => util}/cilfacade.ml | 0 src/common/{ => util}/cilfacade0.ml | 0 src/common/{ => util}/gobConfig.ml | 0 src/common/{ => util}/gobFormat.ml | 0 src/common/{ => util}/jsonSchema.ml | 0 src/common/{ => util}/lazyEval.ml | 0 src/common/{ => util}/messageCategory.ml | 0 src/common/{ => util}/messageUtil.ml | 0 src/common/{ => util}/messages.ml | 0 src/common/{ => util}/options.ml | 2 +- src/common/{ => util}/options.schema.json | 0 src/common/{ => util}/resettableLazy.ml | 0 src/common/{ => util}/resettableLazy.mli | 0 src/common/{ => util}/richVarinfo.ml | 0 src/common/{ => util}/richVarinfo.mli | 0 src/common/{ => util}/timing.ml | 0 src/common/{ => util}/tracing.ml | 0 src/common/{ => util}/xmlUtil.ml | 0 src/goblint_lib.ml | 2 +- 37 files changed, 9 insertions(+), 9 deletions(-) rename src/common/{ => cdomains}/basetype.ml (100%) rename src/common/{ => domains}/lattice.ml (100%) rename src/common/{ => domains}/myCheck.ml (100%) rename src/common/{ => domains}/printable.ml (100%) rename src/common/{ => framework}/analysisState.ml (100%) rename src/common/{ => framework}/controlSpecC.ml (100%) rename src/common/{ => framework}/controlSpecC.mli (100%) rename src/common/{ => framework}/edge.ml (100%) rename src/common/{ => framework}/myCFG.ml (100%) rename src/common/{ => framework}/node.ml (100%) rename src/common/{ => framework}/node0.ml (100%) rename src/common/{ => incremental}/updateCil0.ml (100%) rename src/common/{ => util}/afterConfig.ml (100%) rename src/common/{ => util}/cilType.ml (100%) rename src/common/{ => util}/cilfacade.ml (100%) rename src/common/{ => util}/cilfacade0.ml (100%) rename src/common/{ => util}/gobConfig.ml (100%) rename src/common/{ => util}/gobFormat.ml (100%) rename src/common/{ => util}/jsonSchema.ml (100%) rename src/common/{ => util}/lazyEval.ml (100%) rename src/common/{ => util}/messageCategory.ml (100%) rename src/common/{ => util}/messageUtil.ml (100%) rename src/common/{ => util}/messages.ml (100%) rename src/common/{ => util}/options.ml (98%) rename src/common/{ => util}/options.schema.json (100%) rename src/common/{ => util}/resettableLazy.ml (100%) rename src/common/{ => util}/resettableLazy.mli (100%) rename src/common/{ => util}/richVarinfo.ml (100%) rename src/common/{ => util}/richVarinfo.mli (100%) rename src/common/{ => util}/timing.ml (100%) rename src/common/{ => util}/tracing.ml (100%) rename src/common/{ => util}/xmlUtil.ml (100%) diff --git a/.github/workflows/options.yml b/.github/workflows/options.yml index 84906d4949..40652791fa 100644 --- a/.github/workflows/options.yml +++ b/.github/workflows/options.yml @@ -26,10 +26,10 @@ jobs: run: npm install -g ajv-cli - name: Migrate schema # https://github.com/ajv-validator/ajv-cli/issues/199 - run: ajv migrate -s src/common/options.schema.json + run: ajv migrate -s src/common/util/options.schema.json - name: Validate conf - run: ajv validate -s src/common/options.schema.json -d "conf/**/*.json" + run: ajv validate -s src/common/util/options.schema.json -d "conf/**/*.json" - name: Validate incremental tests - run: ajv validate -s src/common/options.schema.json -d "tests/incremental/*/*.json" + run: ajv validate -s src/common/util/options.schema.json -d "tests/incremental/*/*.json" diff --git a/.readthedocs.yaml b/.readthedocs.yaml index 4827b825ef..08044d195c 100644 --- a/.readthedocs.yaml +++ b/.readthedocs.yaml @@ -20,4 +20,4 @@ build: - pip install json-schema-for-humans post_build: - mkdir _readthedocs/html/jsfh/ - - generate-schema-doc --config-file jsfh.yml src/common/options.schema.json _readthedocs/html/jsfh/ + - generate-schema-doc --config-file jsfh.yml src/common/util/options.schema.json _readthedocs/html/jsfh/ diff --git a/docs/user-guide/configuring.md b/docs/user-guide/configuring.md index 348e15dac4..9a32a14a4c 100644 --- a/docs/user-guide/configuring.md +++ b/docs/user-guide/configuring.md @@ -24,7 +24,7 @@ In `.vscode/settings.json` add the following: "/conf/*.json", "/tests/incremental/*/*.json" ], - "url": "/src/common/options.schema.json" + "url": "/src/common/util/options.schema.json" } ] } diff --git a/src/common/basetype.ml b/src/common/cdomains/basetype.ml similarity index 100% rename from src/common/basetype.ml rename to src/common/cdomains/basetype.ml diff --git a/src/common/lattice.ml b/src/common/domains/lattice.ml similarity index 100% rename from src/common/lattice.ml rename to src/common/domains/lattice.ml diff --git a/src/common/myCheck.ml b/src/common/domains/myCheck.ml similarity index 100% rename from src/common/myCheck.ml rename to src/common/domains/myCheck.ml diff --git a/src/common/printable.ml b/src/common/domains/printable.ml similarity index 100% rename from src/common/printable.ml rename to src/common/domains/printable.ml diff --git a/src/common/dune b/src/common/dune index 03a93a3030..b937ecdd02 100644 --- a/src/common/dune +++ b/src/common/dune @@ -1,4 +1,4 @@ -(include_subdirs no) +(include_subdirs unqualified) (library (name goblint_common) @@ -24,5 +24,5 @@ ppx_deriving_hash ppx_deriving_yojson ppx_blob)) - (preprocessor_deps (file options.schema.json))) + (preprocessor_deps (file util/options.schema.json))) diff --git a/src/common/analysisState.ml b/src/common/framework/analysisState.ml similarity index 100% rename from src/common/analysisState.ml rename to src/common/framework/analysisState.ml diff --git a/src/common/controlSpecC.ml b/src/common/framework/controlSpecC.ml similarity index 100% rename from src/common/controlSpecC.ml rename to src/common/framework/controlSpecC.ml diff --git a/src/common/controlSpecC.mli b/src/common/framework/controlSpecC.mli similarity index 100% rename from src/common/controlSpecC.mli rename to src/common/framework/controlSpecC.mli diff --git a/src/common/edge.ml b/src/common/framework/edge.ml similarity index 100% rename from src/common/edge.ml rename to src/common/framework/edge.ml diff --git a/src/common/myCFG.ml b/src/common/framework/myCFG.ml similarity index 100% rename from src/common/myCFG.ml rename to src/common/framework/myCFG.ml diff --git a/src/common/node.ml b/src/common/framework/node.ml similarity index 100% rename from src/common/node.ml rename to src/common/framework/node.ml diff --git a/src/common/node0.ml b/src/common/framework/node0.ml similarity index 100% rename from src/common/node0.ml rename to src/common/framework/node0.ml diff --git a/src/common/updateCil0.ml b/src/common/incremental/updateCil0.ml similarity index 100% rename from src/common/updateCil0.ml rename to src/common/incremental/updateCil0.ml diff --git a/src/common/afterConfig.ml b/src/common/util/afterConfig.ml similarity index 100% rename from src/common/afterConfig.ml rename to src/common/util/afterConfig.ml diff --git a/src/common/cilType.ml b/src/common/util/cilType.ml similarity index 100% rename from src/common/cilType.ml rename to src/common/util/cilType.ml diff --git a/src/common/cilfacade.ml b/src/common/util/cilfacade.ml similarity index 100% rename from src/common/cilfacade.ml rename to src/common/util/cilfacade.ml diff --git a/src/common/cilfacade0.ml b/src/common/util/cilfacade0.ml similarity index 100% rename from src/common/cilfacade0.ml rename to src/common/util/cilfacade0.ml diff --git a/src/common/gobConfig.ml b/src/common/util/gobConfig.ml similarity index 100% rename from src/common/gobConfig.ml rename to src/common/util/gobConfig.ml diff --git a/src/common/gobFormat.ml b/src/common/util/gobFormat.ml similarity index 100% rename from src/common/gobFormat.ml rename to src/common/util/gobFormat.ml diff --git a/src/common/jsonSchema.ml b/src/common/util/jsonSchema.ml similarity index 100% rename from src/common/jsonSchema.ml rename to src/common/util/jsonSchema.ml diff --git a/src/common/lazyEval.ml b/src/common/util/lazyEval.ml similarity index 100% rename from src/common/lazyEval.ml rename to src/common/util/lazyEval.ml diff --git a/src/common/messageCategory.ml b/src/common/util/messageCategory.ml similarity index 100% rename from src/common/messageCategory.ml rename to src/common/util/messageCategory.ml diff --git a/src/common/messageUtil.ml b/src/common/util/messageUtil.ml similarity index 100% rename from src/common/messageUtil.ml rename to src/common/util/messageUtil.ml diff --git a/src/common/messages.ml b/src/common/util/messages.ml similarity index 100% rename from src/common/messages.ml rename to src/common/util/messages.ml diff --git a/src/common/options.ml b/src/common/util/options.ml similarity index 98% rename from src/common/options.ml rename to src/common/util/options.ml index c9bd41038f..3046f70809 100644 --- a/src/common/options.ml +++ b/src/common/util/options.ml @@ -1,4 +1,4 @@ -(** [src/common/options.schema.json] low-level access. *) +(** [src/common/util/options.schema.json] low-level access. *) open Json_schema diff --git a/src/common/options.schema.json b/src/common/util/options.schema.json similarity index 100% rename from src/common/options.schema.json rename to src/common/util/options.schema.json diff --git a/src/common/resettableLazy.ml b/src/common/util/resettableLazy.ml similarity index 100% rename from src/common/resettableLazy.ml rename to src/common/util/resettableLazy.ml diff --git a/src/common/resettableLazy.mli b/src/common/util/resettableLazy.mli similarity index 100% rename from src/common/resettableLazy.mli rename to src/common/util/resettableLazy.mli diff --git a/src/common/richVarinfo.ml b/src/common/util/richVarinfo.ml similarity index 100% rename from src/common/richVarinfo.ml rename to src/common/util/richVarinfo.ml diff --git a/src/common/richVarinfo.mli b/src/common/util/richVarinfo.mli similarity index 100% rename from src/common/richVarinfo.mli rename to src/common/util/richVarinfo.mli diff --git a/src/common/timing.ml b/src/common/util/timing.ml similarity index 100% rename from src/common/timing.ml rename to src/common/util/timing.ml diff --git a/src/common/tracing.ml b/src/common/util/tracing.ml similarity index 100% rename from src/common/tracing.ml rename to src/common/util/tracing.ml diff --git a/src/common/xmlUtil.ml b/src/common/util/xmlUtil.ml similarity index 100% rename from src/common/xmlUtil.ml rename to src/common/util/xmlUtil.ml diff --git a/src/goblint_lib.ml b/src/goblint_lib.ml index a108058291..0b3829f11c 100644 --- a/src/goblint_lib.ml +++ b/src/goblint_lib.ml @@ -49,7 +49,7 @@ module VarQuery = VarQuery (** {2 Configuration} Runtime configuration is represented as JSON. - Options are specified and documented by the JSON schema [src/common/options.schema.json]. *) + Options are specified and documented by the JSON schema [src/common/util/options.schema.json]. *) module GobConfig = GobConfig module AfterConfig = AfterConfig From 956efd86e8f63aa75bc54808649354c4f7659e8b Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 12 Oct 2023 10:39:24 +0300 Subject: [PATCH 110/140] Fix indentation in moved common library files --- src/common/domains/lattice.ml | 16 ++++++++-------- src/common/util/lazyEval.ml | 14 +++++++------- src/common/util/messageCategory.ml | 4 ++-- 3 files changed, 17 insertions(+), 17 deletions(-) diff --git a/src/common/domains/lattice.ml b/src/common/domains/lattice.ml index 4cdaa8fb9f..79455aea62 100644 --- a/src/common/domains/lattice.ml +++ b/src/common/domains/lattice.ml @@ -4,12 +4,12 @@ module Pretty = GoblintCil.Pretty (* module type Rel = -sig - type t - type relation = Less | Equal | Greater | Uncomparable - val rel : t -> t -> relation - val in_rel : t -> relation -> t -> bool -end *) + sig + type t + type relation = Less | Equal | Greater | Uncomparable + val rel : t -> t -> relation + val in_rel : t -> relation -> t -> bool + end *) (* partial order: elements might not be comparable and no bot/top -> join etc. might fail with exception Uncomparable *) exception Uncomparable @@ -324,14 +324,14 @@ struct match (x,y) with | (`Lifted x, `Lifted y) -> (try `Lifted (Base.widen x y) - with Uncomparable -> `Top) + with Uncomparable -> `Top) | _ -> y let narrow x y = match (x,y) with | (`Lifted x, `Lifted y) -> (try `Lifted (Base.narrow x y) - with Uncomparable -> `Bot) + with Uncomparable -> `Bot) | _ -> x end diff --git a/src/common/util/lazyEval.ml b/src/common/util/lazyEval.ml index e49a5f4693..9007cdd089 100644 --- a/src/common/util/lazyEval.ml +++ b/src/common/util/lazyEval.ml @@ -5,10 +5,10 @@ Node -> CilType -> Printable -> Goblintutil -> GobConfig -> Tracing -> Node *) module Make (M : sig - type t - type result - val eval : t -> result -end) : sig + type t + type result + val eval : t -> result + end) : sig type t val make : M.t -> t val force : t -> M.result @@ -20,8 +20,8 @@ end = struct let force l = match l.value with | `Closure arg -> - let v = M.eval arg in - l.value <- `Computed v; - v + let v = M.eval arg in + l.value <- `Computed v; + v | `Computed v -> v end diff --git a/src/common/util/messageCategory.ml b/src/common/util/messageCategory.ml index 1bb31d6d5b..c70b8faf5f 100644 --- a/src/common/util/messageCategory.ml +++ b/src/common/util/messageCategory.ml @@ -260,8 +260,8 @@ let categoryName = function | Behavior x -> behaviorName x | Integer x -> (match x with - | Overflow -> "Overflow"; - | DivByZero -> "DivByZero") + | Overflow -> "Overflow"; + | DivByZero -> "DivByZero") | Float -> "Float" From 59462c3e2614d79f63a4b8376b2304050f24f6d6 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 12 Oct 2023 10:52:20 +0300 Subject: [PATCH 111/140] Use batteries.unthreaded everywhere to avoid Gobview exception --- gobview | 2 +- src/common/dune | 2 +- src/util/std/dune | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/gobview b/gobview index 41be36b548..42b07f8253 160000 --- a/gobview +++ b/gobview @@ -1 +1 @@ -Subproject commit 41be36b54837b24e6de83740c34e810d3d1afdfb +Subproject commit 42b07f825316052ec030370daf0d00ebe28ec092 diff --git a/src/common/dune b/src/common/dune index b937ecdd02..c9ed9f9db2 100644 --- a/src/common/dune +++ b/src/common/dune @@ -5,7 +5,7 @@ (public_name goblint.common) (wrapped false) ; TODO: wrap (libraries - batteries + batteries.unthreaded zarith goblint_std goblint-cil diff --git a/src/util/std/dune b/src/util/std/dune index c85710a8d6..c6961a1725 100644 --- a/src/util/std/dune +++ b/src/util/std/dune @@ -4,7 +4,7 @@ (name goblint_std) (public_name goblint.std) (libraries - batteries + batteries.unthreaded zarith goblint-cil fpath From a0b376bfa6c587e293172c6d86aa2a1085ddb5c3 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 12 Oct 2023 11:40:03 +0300 Subject: [PATCH 112/140] Add odoc page for package --- src/common/common.mld | 74 +++++++++++++++++++++++++++++++++++++++++++ src/common/dune | 1 + src/dune | 2 ++ src/goblint_lib.ml | 1 + src/index.mld | 51 +++++++++++++++++++++++++++++ 5 files changed, 129 insertions(+) create mode 100644 src/common/common.mld create mode 100644 src/index.mld diff --git a/src/common/common.mld b/src/common/common.mld new file mode 100644 index 0000000000..662c789572 --- /dev/null +++ b/src/common/common.mld @@ -0,0 +1,74 @@ +{0 Library goblint.common} +This library is unwrapped and provides the following top-level modules. +For better context, see {!Goblint_lib} which also documents these modules. + + +{1 Framework} + +{2 CFG} +{!modules: +Node +Edge +MyCFG +} + +{2 Specification} +{!modules: +AnalysisState +ControlSpecC +} + +{2 Configuration} +{!modules: +GobConfig +AfterConfig +JsonSchema +Options +} + + +{1 Domains} +{!modules: +Printable +Lattice +} + +{2 Analysis-specific} + +{3 Other} +{!modules:Basetype} + + +{1 I/O} +{!modules: +Messages +Tracing +} + + +{1 Utilities} +{!modules:Timing} + +{2 General} +{!modules: +LazyEval +ResettableLazy +MessageUtil +XmlUtil +} + +{2 CIL} +{!modules: +CilType +Cilfacade +RichVarinfo +} + + +{1 Library extensions} + +{2 Standard library} +{!modules:GobFormat} + +{2 Other libraries} +{!modules:MyCheck} diff --git a/src/common/dune b/src/common/dune index c9ed9f9db2..c8f1564782 100644 --- a/src/common/dune +++ b/src/common/dune @@ -26,3 +26,4 @@ ppx_blob)) (preprocessor_deps (file util/options.schema.json))) +(documentation) diff --git a/src/dune b/src/dune index df19f85340..acd5348acb 100644 --- a/src/dune +++ b/src/dune @@ -125,3 +125,5 @@ (flags (:standard -warn-error -A -w -unused-var-strict -w -unused-functor-parameter -w +9)) ; https://dune.readthedocs.io/en/stable/faq.html#how-to-make-warnings-non-fatal ) ) + +(documentation) diff --git a/src/goblint_lib.ml b/src/goblint_lib.ml index 0b3829f11c..dadeb2cda1 100644 --- a/src/goblint_lib.ml +++ b/src/goblint_lib.ml @@ -1,3 +1,4 @@ +(** Main library. *) (** {1 Framework} *) diff --git a/src/index.mld b/src/index.mld new file mode 100644 index 0000000000..2afbbc97ae --- /dev/null +++ b/src/index.mld @@ -0,0 +1,51 @@ +{0 goblint index} + +{1 Goblint} +The following libraries make up Goblint's main codebase. + +{2 Library goblint.lib} +{!modules:Goblint_lib} +This library currently contains the majority of Goblint and is in the process of being split into smaller libraries. + +{2 Library goblint.common} +This {{!page-common}unwrapped library} contains various common modules extracted from {!Goblint_lib}. + + +{1 Library extensions} +The following libraries provide extensions to other OCaml libraries. + +{2 Library goblint.std} +{!modules:Goblint_std} + + +{1 Package utilities} +The following libraries provide [goblint] package metadata for executables. + +{2 Library goblint.build-info} +{!modules:Goblint_build_info} +This library is virtual and has the following implementations +- goblint.build-info.dune for native executables, +- goblint.build-info.js for js_of_ocaml executables. + +{2 Library goblint.sites} +{!modules:Goblint_sites} +This library is virtual and has the following implementations +- goblint.sites.dune for native executables, +- goblint.sites.js for js_of_ocaml executables. + + +{1 Independent utilities} +The following libraries provide utilities which are completely independent of Goblint. + +{2 Library goblint.backtrace} +{!modules:Goblint_backtrace} + +{2 Library goblint.timing} +{!modules:Goblint_timing} + + +{1 Vendored} +The following libraries are vendored in Goblint. + +{2 Library goblint.zarith.mlgmpidl} +{!modules:Z_mlgmpidl} From 47cce4f58634308a4326683ab8031499eab2e9e0 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 12 Oct 2023 11:41:24 +0300 Subject: [PATCH 113/140] Use goblint library documentation page in Readthedocs --- mkdocs.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mkdocs.yml b/mkdocs.yml index 558c381e66..428e28078d 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -30,7 +30,7 @@ nav: - 👶 Your first analysis: developer-guide/firstanalysis.md - 🏫 Extending library: developer-guide/extending-library.md - 📢 Messaging: developer-guide/messaging.md - - 🗃️ API reference: https://goblint.github.io/analyzer/ + - 🗃️ API reference: https://goblint.github.io/analyzer/goblint/ - 🚨 Testing: developer-guide/testing.md - 🪲 Debugging: developer-guide/debugging.md - 📉 Profiling: developer-guide/profiling.md From 7ebf97e9ef2f9167898f40bd304880d48f10cb08 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 12 Oct 2023 15:38:49 +0300 Subject: [PATCH 114/140] Fix scripts/goblint-lib-modules.py --- scripts/goblint-lib-modules.py | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/scripts/goblint-lib-modules.py b/scripts/goblint-lib-modules.py index 342f9a76bd..5f02271616 100755 --- a/scripts/goblint-lib-modules.py +++ b/scripts/goblint-lib-modules.py @@ -6,16 +6,20 @@ src_root_path = Path("./src") -goblint_lib_path = src_root_path / "goblint_lib.ml" +goblint_lib_paths = [ + src_root_path / "goblint_lib.ml", + src_root_path / "util" / "std" / "goblint_std.ml", +] goblint_lib_modules = set() -with goblint_lib_path.open() as goblint_lib_file: - for line in goblint_lib_file: - line = line.strip() - m = re.match(r"module (.*) = .*", line) - if m is not None: - module_name = m.group(1) - goblint_lib_modules.add(module_name) +for goblint_lib_path in goblint_lib_paths: + with goblint_lib_path.open() as goblint_lib_file: + for line in goblint_lib_file: + line = line.strip() + m = re.match(r"module (.*) = .*", line) + if m is not None: + module_name = m.group(1) + goblint_lib_modules.add(module_name) src_vendor_path = src_root_path / "vendor" exclude_module_names = set([ @@ -29,15 +33,21 @@ "Mainspec", # libraries + "Goblint_std", "Goblint_timing", "Goblint_backtrace", "Goblint_sites", "Goblint_build_info", + "Dune_build_info", "MessageCategory", # included in Messages "PreValueDomain", # included in ValueDomain "SpecCore", # spec stuff "SpecUtil", # spec stuff + + "ConfigVersion", + "ConfigProfile", + "ConfigOcaml", ]) src_modules = set() From 910a11f903e217efcc946d7d9d988c50575cd3ae Mon Sep 17 00:00:00 2001 From: Michael Schwarz Date: Thu, 12 Oct 2023 14:50:36 +0200 Subject: [PATCH 115/140] Activate `cil.addNestedScopeAttr` when `memOutOfBounds` analysis is active --- src/maingoblint.ml | 1 + tests/regression/74-invalid_deref/08-memset-memcpy-array.c | 7 ++++--- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/maingoblint.ml b/src/maingoblint.ml index 97f35214be..b5998df2d1 100644 --- a/src/maingoblint.ml +++ b/src/maingoblint.ml @@ -135,6 +135,7 @@ let check_arguments () = if get_bool "allfuns" && not (get_bool "exp.earlyglobs") then (set_bool "exp.earlyglobs" true; warn "allfuns enables exp.earlyglobs.\n"); if not @@ List.mem "escape" @@ get_string_list "ana.activated" then warn "Without thread escape analysis, every local variable whose address is taken is considered escaped, i.e., global!"; if List.mem "malloc_null" @@ get_string_list "ana.activated" && not @@ get_bool "sem.malloc.fail" then (set_bool "sem.malloc.fail" true; warn "The malloc_null analysis enables sem.malloc.fail."); + if List.mem "memOutOfBounds" @@ get_string_list "ana.activated" && not @@ get_bool "cil.addNestedScopeAttr" then (set_bool "cil.addNestedScopeAttr" true; warn "The memOutOfBounds analysis enables cil.addNestedScopeAttr."); if get_bool "ana.base.context.int" && not (get_bool "ana.base.context.non-ptr") then (set_bool "ana.base.context.int" false; warn "ana.base.context.int implicitly disabled by ana.base.context.non-ptr"); (* order matters: non-ptr=false, int=true -> int=false cascades to interval=false with warning *) if get_bool "ana.base.context.interval" && not (get_bool "ana.base.context.int") then (set_bool "ana.base.context.interval" false; warn "ana.base.context.interval implicitly disabled by ana.base.context.int"); diff --git a/tests/regression/74-invalid_deref/08-memset-memcpy-array.c b/tests/regression/74-invalid_deref/08-memset-memcpy-array.c index f231ba2dc4..210a61d459 100644 --- a/tests/regression/74-invalid_deref/08-memset-memcpy-array.c +++ b/tests/regression/74-invalid_deref/08-memset-memcpy-array.c @@ -6,13 +6,14 @@ int main(int argc, char const *argv[]) { int arr[42]; // Size should be 168 bytes (with 4 byte ints) int *b = arr; - + int random; + memset(b, 0, 168); //NOWARN memset(b, 0, sizeof(arr)); //NOWARN memset(b, 0, 169); //WARN memset(b, 0, sizeof(arr) + 1); //WARN - + int *c = malloc(sizeof(arr)); // Size should be 168 bytes (with 4 byte ints) memcpy(b, c, 168); //NOWARN memcpy(b, c, sizeof(arr)); //NOWARN @@ -26,7 +27,7 @@ int main(int argc, char const *argv[]) { memset(b, 0, 168); //WARN memcpy(b, c, 168); //WARN } else if (*(argv + 5)) { - int random = rand(); + random = rand(); b = &random; memset(b, 0, 168); //WARN memcpy(b, c, 168); //WARN From fe369158efccfe1c531429f18e03b79b49dab38e Mon Sep 17 00:00:00 2001 From: Michael Schwarz Date: Sat, 14 Oct 2023 11:04:13 +0200 Subject: [PATCH 116/140] Add `AnalysisStateUtil` to `goblint_lib.ml` (#1201) --- src/goblint_lib.ml | 1 + 1 file changed, 1 insertion(+) diff --git a/src/goblint_lib.ml b/src/goblint_lib.ml index dadeb2cda1..a71a0c9684 100644 --- a/src/goblint_lib.ml +++ b/src/goblint_lib.ml @@ -23,6 +23,7 @@ module CfgTools = CfgTools module Analyses = Analyses module Constraints = Constraints module AnalysisState = AnalysisState +module AnalysisStateUtil = AnalysisStateUtil module ControlSpecC = ControlSpecC (** Master control program (MCP) is the analysis specification for the dynamic product of activated analyses. *) From a4261deb3f784720d0806cf92c1c9165d2cbe36e Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Mon, 16 Oct 2023 17:36:23 +0300 Subject: [PATCH 117/140] Add final message for unknown ignored longjmp --- src/framework/constraints.ml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/framework/constraints.ml b/src/framework/constraints.ml index 21f3958a81..95a13ed516 100644 --- a/src/framework/constraints.ml +++ b/src/framework/constraints.ml @@ -1663,7 +1663,8 @@ struct if M.tracing then Messages.tracel "longjmp" "Jumping to %a\n" JmpBufDomain.JmpBufSet.pretty targets; let handle_target target = match target with | JmpBufDomain.BufferEntryOrTop.AllTargets -> - M.warn ~category:Imprecise "Longjmp to potentially invalid target, as contents of buffer %a may be unknown! (imprecision due to heap?)" d_exp env + M.warn ~category:Imprecise "Longjmp to potentially invalid target, as contents of buffer %a may be unknown! (imprecision due to heap?)" d_exp env; + M.msg_final Error ~category:Unsound ~tags:[Category Imprecise; Category Call] "Longjmp to unknown target ignored" | Target (target_node, target_context) -> let target_fundec = Node.find_fundec target_node in if CilType.Fundec.equal target_fundec current_fundec && ControlSpecC.equal target_context (ctx.control_context ()) then ( From 5948ca4212df4c896ee20082a4eb6422c70bd06d Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Mon, 16 Oct 2023 17:37:45 +0300 Subject: [PATCH 118/140] Mark longjmp-top reachability test as TODO --- tests/regression/68-longjmp/56-longjmp-top.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/regression/68-longjmp/56-longjmp-top.c b/tests/regression/68-longjmp/56-longjmp-top.c index 4d57b42fd3..adb3a47476 100644 --- a/tests/regression/68-longjmp/56-longjmp-top.c +++ b/tests/regression/68-longjmp/56-longjmp-top.c @@ -15,7 +15,7 @@ int main() { longjmp(*buf_ptr, 1); // NO CRASH: problem?! } else { - __goblint_check(1); // reachable + __goblint_check(1); // TODO reachable: https://github.com/goblint/analyzer/pull/1210#discussion_r1350021903 } return 0; } From 32be7d50615878bb400b6d665d5bb589be28b79c Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Fri, 20 Oct 2023 13:39:23 +0300 Subject: [PATCH 119/140] Improve names of some global constraint variables --- src/analyses/commonPriv.ml | 2 +- src/framework/constraints.ml | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/analyses/commonPriv.ml b/src/analyses/commonPriv.ml index db75455b40..793978980b 100644 --- a/src/analyses/commonPriv.ml +++ b/src/analyses/commonPriv.ml @@ -84,7 +84,7 @@ struct module V = struct (* TODO: Either3? *) - include Printable.Either (Printable.Either (VMutex) (VMutexInits)) (VGlobal) + include Printable.Either (struct include Printable.Either (VMutex) (VMutexInits) let name () = "mutex" end) (VGlobal) let name () = "MutexGlobals" let mutex x: t = `Left (`Left x) let mutex_inits: t = `Left (`Right ()) diff --git a/src/framework/constraints.ml b/src/framework/constraints.ml index 95a13ed516..812d056de4 100644 --- a/src/framework/constraints.ml +++ b/src/framework/constraints.ml @@ -1467,6 +1467,7 @@ struct module V = struct include Printable.Either (S.V) (Printable.Either (Printable.Prod (Node) (C)) (Printable.Prod (CilType.Fundec) (C))) + let name () = "longjmp" let s x = `Left x let longjmpto x = `Right (`Left x) let longjmpret x = `Right (`Right x) From af904ac55762f3b9bb59bce54a13ed8e311894d1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 23 Oct 2023 20:19:25 +0000 Subject: [PATCH 120/140] Bump actions/setup-node from 3 to 4 Bumps [actions/setup-node](https://github.com/actions/setup-node) from 3 to 4. - [Release notes](https://github.com/actions/setup-node/releases) - [Commits](https://github.com/actions/setup-node/compare/v3...v4) --- updated-dependencies: - dependency-name: actions/setup-node dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/locked.yml | 2 +- .github/workflows/metadata.yml | 2 +- .github/workflows/options.yml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/locked.yml b/.github/workflows/locked.yml index 007ea34619..65dfbe7bac 100644 --- a/.github/workflows/locked.yml +++ b/.github/workflows/locked.yml @@ -153,7 +153,7 @@ jobs: ocaml-compiler: ${{ matrix.ocaml-compiler }} - name: Set up Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: node-version: ${{ matrix.node-version }} diff --git a/.github/workflows/metadata.yml b/.github/workflows/metadata.yml index 1092606bc6..6c7360f9e3 100644 --- a/.github/workflows/metadata.yml +++ b/.github/workflows/metadata.yml @@ -39,7 +39,7 @@ jobs: uses: actions/checkout@v4 - name: Set up Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: node-version: ${{ matrix.node-version }} diff --git a/.github/workflows/options.yml b/.github/workflows/options.yml index 40652791fa..94c49e4bf6 100644 --- a/.github/workflows/options.yml +++ b/.github/workflows/options.yml @@ -18,7 +18,7 @@ jobs: uses: actions/checkout@v4 - name: Set up Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: node-version: ${{ matrix.node-version }} From 0cf9bc498741c24abda05007134c067f297a1b72 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 26 Oct 2023 10:28:06 +0300 Subject: [PATCH 121/140] Add smtprc-tid unsound case --- tests/regression/03-practical/32-smtprc-tid.c | 38 +++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 tests/regression/03-practical/32-smtprc-tid.c diff --git a/tests/regression/03-practical/32-smtprc-tid.c b/tests/regression/03-practical/32-smtprc-tid.c new file mode 100644 index 0000000000..1d4810ee2e --- /dev/null +++ b/tests/regression/03-practical/32-smtprc-tid.c @@ -0,0 +1,38 @@ +#include +#include + +int threads_total = 4; +pthread_t *tids; + +void *cleaner(void *arg) { + while (1) { + for (int i = 0; i < threads_total; i++) { + if (tids[i]) { // RACE! + if (!pthread_join(tids[i], NULL)) // RACE! + tids[i] = 0; // RACE! + } + } + } + return NULL; +} + +void *thread(int i) { // wrong argument type is important + tids[i] = pthread_self(); // RACE! + return NULL; +} + +int main() { + pthread_t tid; + tids = malloc(threads_total * sizeof(pthread_t)); + + for(int i = 0; i < threads_total; i++) + tids[i] = 0; + + pthread_create(&tid, NULL, cleaner, NULL); + + for(int i = 0; i < threads_total; i++) { + pthread_create(&tid, NULL, thread, (int *)i); // cast is important + } + + return 0; +} From 2a958bd7e1a71c0216a0d49317796a45fd13ddf7 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 20 Sep 2023 17:47:35 +0300 Subject: [PATCH 122/140] Fix smtprc-tid unsoundness --- src/analyses/base.ml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/analyses/base.ml b/src/analyses/base.ml index caa2a41533..6536a9c496 100644 --- a/src/analyses/base.ml +++ b/src/analyses/base.ml @@ -399,6 +399,8 @@ struct Int (if AD.is_bot (AD.meet p1 p2) then ID.of_int ik BI.one else match eq p1 p2 with Some x when x -> ID.of_int ik BI.zero | _ -> bool_top ik) | IndexPI when AD.to_string p2 = ["all_index"] -> addToAddrOp p1 (ID.top_of (Cilfacade.ptrdiff_ikind ())) + | IndexPI | PlusPI -> + addToAddrOp p1 (AD.to_int p2) (* sometimes index is AD for some reason... *) | _ -> VD.top () end (* For other values, we just give up! *) From 6899d444f27c1f434ade07565ab5d23a631ea753 Mon Sep 17 00:00:00 2001 From: Karoliine Holter Date: Fri, 27 Oct 2023 15:10:48 +0300 Subject: [PATCH 123/140] Add --enable ana.sv-comp.functions to 20-race-2_1-container_of.c --- tests/regression/10-synch/20-race-2_1-container_of.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/regression/10-synch/20-race-2_1-container_of.c b/tests/regression/10-synch/20-race-2_1-container_of.c index 6083cf4ca0..940649c43b 100644 --- a/tests/regression/10-synch/20-race-2_1-container_of.c +++ b/tests/regression/10-synch/20-race-2_1-container_of.c @@ -1,4 +1,4 @@ -// PARAM: --set ana.activated[+] thread --set ana.path_sens[+] threadflag +// PARAM: --set ana.activated[+] thread --set ana.path_sens[+] threadflag --enable ana.sv-comp.functions #include #include #include @@ -60,7 +60,7 @@ int my_drv_probe(struct my_data *data) { ldv_assert(data->shared.a==0); // NORACE ldv_assert(data->shared.b==0); // NORACE - int res = __VERIFIER_nondet_int(); + int res = magic(); if(res) goto exit; //register callback From 2c0a08f0e356d7e92fff2db874d081e38831e272 Mon Sep 17 00:00:00 2001 From: Karoliine Holter Date: Sun, 29 Oct 2023 20:14:11 +0200 Subject: [PATCH 124/140] Fix accident in 20 10 test --- tests/regression/10-synch/20-race-2_1-container_of.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/regression/10-synch/20-race-2_1-container_of.c b/tests/regression/10-synch/20-race-2_1-container_of.c index 940649c43b..04d5facbb7 100644 --- a/tests/regression/10-synch/20-race-2_1-container_of.c +++ b/tests/regression/10-synch/20-race-2_1-container_of.c @@ -60,7 +60,7 @@ int my_drv_probe(struct my_data *data) { ldv_assert(data->shared.a==0); // NORACE ldv_assert(data->shared.b==0); // NORACE - int res = magic(); + int res = __VERIFIER_nondet_int(); if(res) goto exit; //register callback From 7ad12249c111c7dbdb906be7f57311c49a3a15be Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Mon, 30 Oct 2023 16:52:50 +0200 Subject: [PATCH 125/140] Move GraphML witness options into witness.graphml (issue #1217) --- conf/ldv-races.json | 6 +- conf/svcomp-yaml.json | 4 +- conf/svcomp.json | 6 +- conf/svcomp21.json | 4 +- ...vcomp22-intervals-novareq-affeq-apron.json | 6 +- ...comp22-intervals-novareq-affeq-native.json | 6 +- ...omp22-intervals-novareq-octagon-apron.json | 6 +- ...p22-intervals-novareq-polyhedra-apron.json | 6 +- conf/svcomp22.json | 6 +- conf/svcomp23.json | 6 +- src/common/util/options.schema.json | 93 ++++++++++--------- src/framework/control.ml | 2 +- src/witness/myARG.ml | 4 +- src/witness/witness.ml | 14 +-- sv-comp/sv-comp-run-no-overflow.py | 2 +- sv-comp/sv-comp-run.py | 2 +- .../observer/path_nofun_true-unreach-call.c | 2 +- 17 files changed, 101 insertions(+), 74 deletions(-) diff --git a/conf/ldv-races.json b/conf/ldv-races.json index 01c60efc8d..2840bb368c 100644 --- a/conf/ldv-races.json +++ b/conf/ldv-races.json @@ -53,8 +53,10 @@ } }, "witness": { - "id": "enumerate", - "unknown": false + "graphml": { + "id": "enumerate", + "unknown": false + } }, "solver": "td3", "sem": { diff --git a/conf/svcomp-yaml.json b/conf/svcomp-yaml.json index e09d1c80d7..10a977ff47 100644 --- a/conf/svcomp-yaml.json +++ b/conf/svcomp-yaml.json @@ -76,7 +76,9 @@ "region-offsets": true }, "witness": { - "enabled": false, + "graphml": { + "enabled": false + }, "yaml": { "enabled": true }, diff --git a/conf/svcomp.json b/conf/svcomp.json index 913d43784b..87fef277c3 100644 --- a/conf/svcomp.json +++ b/conf/svcomp.json @@ -90,8 +90,10 @@ } }, "witness": { - "id": "enumerate", - "unknown": false + "graphml": { + "id": "enumerate", + "unknown": false + } }, "pre": { "enabled": false diff --git a/conf/svcomp21.json b/conf/svcomp21.json index a19bfdb9d0..eda5cdfb88 100644 --- a/conf/svcomp21.json +++ b/conf/svcomp21.json @@ -64,6 +64,8 @@ } }, "witness": { - "id": "enumerate" + "graphml": { + "id": "enumerate" + } } } diff --git a/conf/svcomp22-intervals-novareq-affeq-apron.json b/conf/svcomp22-intervals-novareq-affeq-apron.json index 7f72f5d0d8..1dafe0a76d 100644 --- a/conf/svcomp22-intervals-novareq-affeq-apron.json +++ b/conf/svcomp22-intervals-novareq-affeq-apron.json @@ -68,7 +68,9 @@ } }, "witness": { - "id": "enumerate", - "unknown": false + "graphml": { + "id": "enumerate", + "unknown": false + } } } \ No newline at end of file diff --git a/conf/svcomp22-intervals-novareq-affeq-native.json b/conf/svcomp22-intervals-novareq-affeq-native.json index 3ae1b19788..47b5cbbd8f 100644 --- a/conf/svcomp22-intervals-novareq-affeq-native.json +++ b/conf/svcomp22-intervals-novareq-affeq-native.json @@ -65,7 +65,9 @@ } }, "witness": { - "id": "enumerate", - "unknown": false + "graphml": { + "id": "enumerate", + "unknown": false + } } } diff --git a/conf/svcomp22-intervals-novareq-octagon-apron.json b/conf/svcomp22-intervals-novareq-octagon-apron.json index 3bf149800e..c6c7144cf6 100644 --- a/conf/svcomp22-intervals-novareq-octagon-apron.json +++ b/conf/svcomp22-intervals-novareq-octagon-apron.json @@ -68,7 +68,9 @@ } }, "witness": { - "id": "enumerate", - "unknown": false + "graphml": { + "id": "enumerate", + "unknown": false + } } } diff --git a/conf/svcomp22-intervals-novareq-polyhedra-apron.json b/conf/svcomp22-intervals-novareq-polyhedra-apron.json index e4e513415a..e636b6fcdf 100644 --- a/conf/svcomp22-intervals-novareq-polyhedra-apron.json +++ b/conf/svcomp22-intervals-novareq-polyhedra-apron.json @@ -68,7 +68,9 @@ } }, "witness": { - "id": "enumerate", - "unknown": false + "graphml": { + "id": "enumerate", + "unknown": false + } } } diff --git a/conf/svcomp22.json b/conf/svcomp22.json index 85ea693375..09113a38c9 100644 --- a/conf/svcomp22.json +++ b/conf/svcomp22.json @@ -67,7 +67,9 @@ } }, "witness": { - "id": "enumerate", - "unknown": false + "graphml": { + "id": "enumerate", + "unknown": false + } } } diff --git a/conf/svcomp23.json b/conf/svcomp23.json index 56474fbe2b..6f404060ba 100644 --- a/conf/svcomp23.json +++ b/conf/svcomp23.json @@ -90,7 +90,9 @@ } }, "witness": { - "id": "enumerate", - "unknown": false + "graphml": { + "id": "enumerate", + "unknown": false + } } } diff --git a/src/common/util/options.schema.json b/src/common/util/options.schema.json index 400dde06dc..5f2081e8d6 100644 --- a/src/common/util/options.schema.json +++ b/src/common/util/options.schema.json @@ -2279,24 +2279,56 @@ "title": "witness", "type": "object", "properties": { - "enabled": { - "title": "witness.enabled", - "description": "Output witness", - "type": "boolean", - "default": true - }, - "path": { - "title": "witness.path", - "description": "Witness output path", - "type": "string", - "default": "witness.graphml" - }, - "id": { - "title": "witness.id", - "description": "Which witness node IDs to use? node/enumerate", - "type": "string", - "enum": ["node", "enumerate"], - "default": "node" + "graphml": { + "title": "witness.graphml", + "type": "object", + "properties": { + "enabled": { + "title": "witness.graphml.enabled", + "description": "Output GraphML witness", + "type": "boolean", + "default": true + }, + "path": { + "title": "witness.graphml.path", + "description": "GraphML witness output path", + "type": "string", + "default": "witness.graphml" + }, + "id": { + "title": "witness.graphml.id", + "description": "Which witness node IDs to use? node/enumerate", + "type": "string", + "enum": ["node", "enumerate"], + "default": "node" + }, + "minimize": { + "title": "witness.graphml.minimize", + "description": "Try to minimize the witness", + "type": "boolean", + "default": false + }, + "uncil": { + "title": "witness.graphml.uncil", + "description": + "Try to undo CIL control flow transformations in witness", + "type": "boolean", + "default": false + }, + "stack": { + "title": "witness.graphml.stack", + "description": "Construct stacktrace-based witness nodes", + "type": "boolean", + "default": true + }, + "unknown": { + "title": "witness.graphml.unknown", + "description": "Output witness for unknown result", + "type": "boolean", + "default": true + } + }, + "additionalProperties": false }, "invariant": { "title": "witness.invariant", @@ -2376,31 +2408,6 @@ }, "additionalProperties": false }, - "minimize": { - "title": "witness.minimize", - "description": "Try to minimize the witness", - "type": "boolean", - "default": false - }, - "uncil": { - "title": "witness.uncil", - "description": - "Try to undo CIL control flow transformations in witness", - "type": "boolean", - "default": false - }, - "stack": { - "title": "witness.stack", - "description": "Construct stacktrace-based witness nodes", - "type": "boolean", - "default": true - }, - "unknown": { - "title": "witness.unknown", - "description": "Output witness for unknown result", - "type": "boolean", - "default": true - }, "yaml": { "title": "witness.yaml", "type": "object", diff --git a/src/framework/control.ml b/src/framework/control.ml index 9baa2dd1ca..fe43deb45f 100644 --- a/src/framework/control.ml +++ b/src/framework/control.ml @@ -14,7 +14,7 @@ module type S2S = functor (X : Spec) -> Spec (* spec is lazy, so HConsed table in Hashcons lifters is preserved between analyses in server mode *) let spec_module: (module Spec) Lazy.t = lazy ( GobConfig.building_spec := true; - let arg_enabled = (get_bool "ana.sv-comp.enabled" && get_bool "witness.enabled") || get_bool "exp.arg" in + let arg_enabled = (get_bool "ana.sv-comp.enabled" && get_bool "witness.graphml.enabled") || get_bool "exp.arg" in let open Batteries in (* apply functor F on module X if opt is true *) let lift opt (module F : S2S) (module X : Spec) = (module (val if opt then (module F (X)) else (module X) : Spec) : Spec) in diff --git a/src/witness/myARG.ml b/src/witness/myARG.ml index 62c705f5b1..068aed7a22 100644 --- a/src/witness/myARG.ml +++ b/src/witness/myARG.ml @@ -320,7 +320,7 @@ struct let rec next_opt' n = match n with - | Statement {sid; skind=If (_, _, _, loc, eloc); _} when GobConfig.get_bool "witness.uncil" -> (* TODO: use elocs instead? *) + | Statement {sid; skind=If (_, _, _, loc, eloc); _} when GobConfig.get_bool "witness.graphml.uncil" -> (* TODO: use elocs instead? *) let (e, if_true_next_n, if_false_next_n) = partition_if_next (Arg.next n) in (* avoid infinite recursion with sid <> sid2 in if_nondet_var *) (* TODO: why physical comparison if_false_next_n != n doesn't work? *) @@ -373,7 +373,7 @@ struct Question(e_cond, e_true, e_false, Cilfacade.typeOf e_false) let next_opt' n = match n with - | Statement {skind=If (_, _, _, loc, eloc); _} when GobConfig.get_bool "witness.uncil" -> (* TODO: use eloc instead? *) + | Statement {skind=If (_, _, _, loc, eloc); _} when GobConfig.get_bool "witness.graphml.uncil" -> (* TODO: use eloc instead? *) let (e_cond, if_true_next_n, if_false_next_n) = partition_if_next (Arg.next n) in if Node.location if_true_next_n = loc && Node.location if_false_next_n = loc then match Arg.next if_true_next_n, Arg.next if_false_next_n with diff --git a/src/witness/witness.ml b/src/witness/witness.ml index 9f5a3c1801..2d94f4a18d 100644 --- a/src/witness/witness.ml +++ b/src/witness/witness.ml @@ -13,7 +13,7 @@ let write_file filename (module Task:Task) (module TaskResult:WitnessTaskResult) let module Invariant = WitnessUtil.Invariant (Task) in let module TaskResult = - (val if get_bool "witness.stack" then + (val if get_bool "witness.graphml.stack" then (module StackTaskResult (Task.Cfg) (TaskResult) : WitnessTaskResult) else (module TaskResult) @@ -24,7 +24,7 @@ let write_file filename (module Task:Task) (module TaskResult:WitnessTaskResult) struct (* type node = N.t type edge = TaskResult.Arg.Edge.t *) - let minwitness = get_bool "witness.minimize" + let minwitness = get_bool "witness.graphml.minimize" let is_interesting_real from_node edge to_node = (* TODO: don't duplicate this logic with write_node, write_edge *) (* startlines aren't currently interesting because broken, see below *) @@ -58,12 +58,12 @@ let write_file filename (module Task:Task) (module TaskResult:WitnessTaskResult) let module N = Arg.Node in let module GML = XmlGraphMlWriter in let module GML = - (val match get_string "witness.id" with + (val match get_string "witness.graphml.id" with | "node" -> (module ArgNodeGraphMlWriter (N) (GML) : GraphMlWriter with type node = N.t) | "enumerate" -> (module EnumerateNodeGraphMlWriter (N) (GML)) - | _ -> failwith "witness.id: illegal value" + | _ -> failwith "witness.graphml.id: illegal value" ) in let module GML = DeDupGraphMlWriter (N) (GML) in @@ -305,7 +305,7 @@ struct let determine_result entrystates (module Task:Task): (module WitnessTaskResult) = let module Arg: BiArgInvariant = - (val if GobConfig.get_bool "witness.enabled" then ( + (val if GobConfig.get_bool "witness.graphml.enabled" then ( let module Arg = (val ArgTool.create entrystates) in let module Arg = struct @@ -576,8 +576,8 @@ struct print_task_result (module TaskResult); - if get_bool "witness.enabled" && (TaskResult.result <> Result.Unknown || get_bool "witness.unknown") then ( - let witness_path = get_string "witness.path" in + if get_bool "witness.graphml.enabled" && (TaskResult.result <> Result.Unknown || get_bool "witness.graphml.unknown") then ( + let witness_path = get_string "witness.graphml.path" in Timing.wrap "write" (write_file witness_path (module Task)) (module TaskResult) ) diff --git a/sv-comp/sv-comp-run-no-overflow.py b/sv-comp/sv-comp-run-no-overflow.py index a3461b1a64..88ee2c0e53 100755 --- a/sv-comp/sv-comp-run-no-overflow.py +++ b/sv-comp/sv-comp-run-no-overflow.py @@ -13,7 +13,7 @@ OVERVIEW = False # with True Goblint isn't executed # TODO: don't hard-code specification -GOBLINT_COMMAND = "./goblint --conf conf/svcomp21.json --set ana.specification ./tests/sv-comp/no-overflow.prp --set witness.path {witness_filename} {code_filename} -v" +GOBLINT_COMMAND = "./goblint --conf conf/svcomp21.json --set ana.specification ./tests/sv-comp/no-overflow.prp --set witness.graphml.path {witness_filename} {code_filename} -v" TIMEOUT = 10 # with some int that's Goblint timeout for single execution START = 1 EXIT_ON_ERROR = True diff --git a/sv-comp/sv-comp-run.py b/sv-comp/sv-comp-run.py index af7cada051..977aa69ab6 100755 --- a/sv-comp/sv-comp-run.py +++ b/sv-comp/sv-comp-run.py @@ -13,7 +13,7 @@ OVERVIEW = False # with True Goblint isn't executed # TODO: don't hard-code specification -GOBLINT_COMMAND = "./goblint --conf conf/svcomp21.json --set ana.specification ./tests/sv-comp/unreach-call-__VERIFIER_error.prp --set witness.path {witness_filename} {code_filename}" +GOBLINT_COMMAND = "./goblint --conf conf/svcomp21.json --set ana.specification ./tests/sv-comp/unreach-call-__VERIFIER_error.prp --set witness.graphml.path {witness_filename} {code_filename}" TIMEOUT = 30 # with some int that's Goblint timeout for single execution START = 1 EXIT_ON_ERROR = True diff --git a/tests/sv-comp/observer/path_nofun_true-unreach-call.c b/tests/sv-comp/observer/path_nofun_true-unreach-call.c index 0cb70d23e9..cf1191e9fd 100644 --- a/tests/sv-comp/observer/path_nofun_true-unreach-call.c +++ b/tests/sv-comp/observer/path_nofun_true-unreach-call.c @@ -21,4 +21,4 @@ int main() return 0; } -// ./goblint --enable ana.sv-comp --enable ana.wp --enable witness.uncil --disable ana.int.def_exc --enable ana.int.interval --set ana.activated '["base"]' --html tests/sv-comp/observer/path_nofun_true-unreach-call.c +// ./goblint --enable ana.sv-comp --enable ana.wp --enable witness.graphml.uncil --disable ana.int.def_exc --enable ana.int.interval --set ana.activated '["base"]' --html tests/sv-comp/observer/path_nofun_true-unreach-call.c From 8399258dc31e0f12bbeea04be749f730bac080e0 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Mon, 30 Oct 2023 17:01:12 +0200 Subject: [PATCH 126/140] Disable witness.graphml.enabled by default --- conf/ldv-races.json | 1 + conf/svcomp.json | 1 + conf/svcomp21.json | 1 + conf/svcomp22-intervals-novareq-affeq-apron.json | 1 + conf/svcomp22-intervals-novareq-affeq-native.json | 1 + conf/svcomp22-intervals-novareq-octagon-apron.json | 1 + conf/svcomp22-intervals-novareq-polyhedra-apron.json | 1 + conf/svcomp22.json | 1 + conf/svcomp23.json | 1 + src/common/util/options.schema.json | 2 +- 10 files changed, 10 insertions(+), 1 deletion(-) diff --git a/conf/ldv-races.json b/conf/ldv-races.json index 2840bb368c..8db800d74c 100644 --- a/conf/ldv-races.json +++ b/conf/ldv-races.json @@ -54,6 +54,7 @@ }, "witness": { "graphml": { + "enabled": true, "id": "enumerate", "unknown": false } diff --git a/conf/svcomp.json b/conf/svcomp.json index 87fef277c3..2c310c076d 100644 --- a/conf/svcomp.json +++ b/conf/svcomp.json @@ -91,6 +91,7 @@ }, "witness": { "graphml": { + "enabled": true, "id": "enumerate", "unknown": false } diff --git a/conf/svcomp21.json b/conf/svcomp21.json index eda5cdfb88..2e36e61d0c 100644 --- a/conf/svcomp21.json +++ b/conf/svcomp21.json @@ -65,6 +65,7 @@ }, "witness": { "graphml": { + "enabled": true, "id": "enumerate" } } diff --git a/conf/svcomp22-intervals-novareq-affeq-apron.json b/conf/svcomp22-intervals-novareq-affeq-apron.json index 1dafe0a76d..f7f7662b6a 100644 --- a/conf/svcomp22-intervals-novareq-affeq-apron.json +++ b/conf/svcomp22-intervals-novareq-affeq-apron.json @@ -69,6 +69,7 @@ }, "witness": { "graphml": { + "enabled": true, "id": "enumerate", "unknown": false } diff --git a/conf/svcomp22-intervals-novareq-affeq-native.json b/conf/svcomp22-intervals-novareq-affeq-native.json index 47b5cbbd8f..00db00f30f 100644 --- a/conf/svcomp22-intervals-novareq-affeq-native.json +++ b/conf/svcomp22-intervals-novareq-affeq-native.json @@ -66,6 +66,7 @@ }, "witness": { "graphml": { + "enabled": true, "id": "enumerate", "unknown": false } diff --git a/conf/svcomp22-intervals-novareq-octagon-apron.json b/conf/svcomp22-intervals-novareq-octagon-apron.json index c6c7144cf6..a0c09e8937 100644 --- a/conf/svcomp22-intervals-novareq-octagon-apron.json +++ b/conf/svcomp22-intervals-novareq-octagon-apron.json @@ -69,6 +69,7 @@ }, "witness": { "graphml": { + "enabled": true, "id": "enumerate", "unknown": false } diff --git a/conf/svcomp22-intervals-novareq-polyhedra-apron.json b/conf/svcomp22-intervals-novareq-polyhedra-apron.json index e636b6fcdf..3a478bf687 100644 --- a/conf/svcomp22-intervals-novareq-polyhedra-apron.json +++ b/conf/svcomp22-intervals-novareq-polyhedra-apron.json @@ -69,6 +69,7 @@ }, "witness": { "graphml": { + "enabled": true, "id": "enumerate", "unknown": false } diff --git a/conf/svcomp22.json b/conf/svcomp22.json index 09113a38c9..316c3c5534 100644 --- a/conf/svcomp22.json +++ b/conf/svcomp22.json @@ -68,6 +68,7 @@ }, "witness": { "graphml": { + "enabled": true, "id": "enumerate", "unknown": false } diff --git a/conf/svcomp23.json b/conf/svcomp23.json index 6f404060ba..af584f1593 100644 --- a/conf/svcomp23.json +++ b/conf/svcomp23.json @@ -91,6 +91,7 @@ }, "witness": { "graphml": { + "enabled": true, "id": "enumerate", "unknown": false } diff --git a/src/common/util/options.schema.json b/src/common/util/options.schema.json index 5f2081e8d6..8255be2b48 100644 --- a/src/common/util/options.schema.json +++ b/src/common/util/options.schema.json @@ -2287,7 +2287,7 @@ "title": "witness.graphml.enabled", "description": "Output GraphML witness", "type": "boolean", - "default": true + "default": false }, "path": { "title": "witness.graphml.path", From a2a4fa2be47c1f2fc2f3eff167c9e57db9e346ee Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Mon, 30 Oct 2023 17:11:28 +0200 Subject: [PATCH 127/140] Don't output trivial congruence invariant (closes #1218) --- src/cdomains/intDomain.ml | 1 + 1 file changed, 1 insertion(+) diff --git a/src/cdomains/intDomain.ml b/src/cdomains/intDomain.ml index 748df62300..3bc84ae676 100644 --- a/src/cdomains/intDomain.ml +++ b/src/cdomains/intDomain.ml @@ -3274,6 +3274,7 @@ struct let invariant_ikind e ik x = match x with + | x when is_top x -> Invariant.top () | Some (c, m) when m =: Ints_t.zero -> if get_bool "witness.invariant.exact" then let c = Ints_t.to_bigint c in From 783442572bdc03837dd1378c71994e4f53bae360 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Mon, 30 Oct 2023 17:27:09 +0200 Subject: [PATCH 128/140] Forbid witness.graphml.enabled outside of SV-COMP mode --- src/framework/control.ml | 2 +- src/maingoblint.ml | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/framework/control.ml b/src/framework/control.ml index fe43deb45f..948dce6075 100644 --- a/src/framework/control.ml +++ b/src/framework/control.ml @@ -14,7 +14,7 @@ module type S2S = functor (X : Spec) -> Spec (* spec is lazy, so HConsed table in Hashcons lifters is preserved between analyses in server mode *) let spec_module: (module Spec) Lazy.t = lazy ( GobConfig.building_spec := true; - let arg_enabled = (get_bool "ana.sv-comp.enabled" && get_bool "witness.graphml.enabled") || get_bool "exp.arg" in + let arg_enabled = get_bool "witness.graphml.enabled" || get_bool "exp.arg" in let open Batteries in (* apply functor F on module X if opt is true *) let lift opt (module F : S2S) (module X : Spec) = (module (val if opt then (module F (X)) else (module X) : Spec) : Spec) in diff --git a/src/maingoblint.ml b/src/maingoblint.ml index b5998df2d1..6c55f43ba1 100644 --- a/src/maingoblint.ml +++ b/src/maingoblint.ml @@ -160,7 +160,8 @@ let check_arguments () = ^ String.concat " and " @@ List.map (fun s -> "'" ^ s ^ "'") imprecise_options) ); if get_bool "solvers.td3.space" && get_bool "solvers.td3.remove-wpoint" then fail "solvers.td3.space is incompatible with solvers.td3.remove-wpoint"; - if get_bool "solvers.td3.space" && get_string "solvers.td3.side_widen" = "sides-local" then fail "solvers.td3.space is incompatible with solvers.td3.side_widen = 'sides-local'" + if get_bool "solvers.td3.space" && get_string "solvers.td3.side_widen" = "sides-local" then fail "solvers.td3.space is incompatible with solvers.td3.side_widen = 'sides-local'"; + if not (get_bool "ana.sv-comp.enabled") && get_bool "witness.graphml.enabled" then fail "witness.graphml.enabled: cannot generate GraphML witness without SV-COMP mode (ana.sv-comp.enabled)" (** Initialize some globals in other modules. *) let handle_flags () = From e01caccff051316ecb3ff26ba176656f06a9fb76 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Mon, 30 Oct 2023 17:31:30 +0200 Subject: [PATCH 129/140] Disable witness.invariant.accessed by default Makes access analysis more expensive --- src/common/util/options.schema.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/common/util/options.schema.json b/src/common/util/options.schema.json index 8255be2b48..188e5a77e8 100644 --- a/src/common/util/options.schema.json +++ b/src/common/util/options.schema.json @@ -2365,7 +2365,7 @@ "title": "witness.invariant.accessed", "description": "Only emit invariants for locally accessed variables", "type": "boolean", - "default": true + "default": false }, "full": { "title": "witness.invariant.full", From 6cd62e5163aaaa5deb6ac046d6ab7995e358d1a1 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Mon, 30 Oct 2023 17:39:48 +0200 Subject: [PATCH 130/140] Update witness timings --- src/witness/witness.ml | 7 ++----- src/witness/yamlWitness.ml | 3 +++ 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/witness/witness.ml b/src/witness/witness.ml index 2d94f4a18d..af2e1c03ec 100644 --- a/src/witness/witness.ml +++ b/src/witness/witness.ml @@ -572,13 +572,13 @@ struct let write entrystates = let module Task = (val (BatOption.get !task)) in - let module TaskResult = (val (Timing.wrap "determine" (determine_result entrystates) (module Task))) in + let module TaskResult = (val (Timing.wrap "sv-comp result" (determine_result entrystates) (module Task))) in print_task_result (module TaskResult); if get_bool "witness.graphml.enabled" && (TaskResult.result <> Result.Unknown || get_bool "witness.graphml.unknown") then ( let witness_path = get_string "witness.graphml.path" in - Timing.wrap "write" (write_file witness_path (module Task)) (module TaskResult) + Timing.wrap "graphml witness" (write_file witness_path (module Task)) (module TaskResult) ) let write entrystates = @@ -595,7 +595,4 @@ struct ) else write entrystates - - let write entrystates = - Timing.wrap "witness" write entrystates end diff --git a/src/witness/yamlWitness.ml b/src/witness/yamlWitness.ml index 72ff21f6bd..9e8ebeff51 100644 --- a/src/witness/yamlWitness.ml +++ b/src/witness/yamlWitness.ml @@ -392,6 +392,9 @@ struct ]; yaml_entries_to_file yaml_entries (Fpath.v (GobConfig.get_string "witness.yaml.path")) + + let write () = + Timing.wrap "yaml witness" write () end From 1cf3942190226126befdac561159c15758153a52 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Tue, 31 Oct 2023 16:07:47 +0200 Subject: [PATCH 131/140] Make memsafety autotuner enable ana.arrayoob (PR #1201) https://github.com/goblint/analyzer/pull/1201#issuecomment-1787126733 --- src/autoTune.ml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/autoTune.ml b/src/autoTune.ml index 186d930189..b96848c841 100644 --- a/src/autoTune.ml +++ b/src/autoTune.ml @@ -218,6 +218,7 @@ let focusOnMemSafetySpecification () = enableAnalyses uafAna | ValidDeref -> (* Enable the memOutOfBounds analysis *) let memOobAna = ["memOutOfBounds"] in + set_bool "ana.arrayoob" true; print_endline "Setting \"cil.addNestedScopeAttr\" to true"; set_bool "cil.addNestedScopeAttr" true; print_endline @@ "Specification: ValidDeref -> enabling memOutOfBounds analysis \"" ^ (String.concat ", " memOobAna) ^ "\""; @@ -232,6 +233,7 @@ let focusOnMemSafetySpecification () = print_endline @@ "Specification: ValidMemtrack and ValidMemcleanup -> enabling memLeak analysis \"" ^ (String.concat ", " memLeakAna) ^ "\""; enableAnalyses memLeakAna | MemorySafety -> (* TODO: This is a temporary solution for the memory safety category *) + set_bool "ana.arrayoob" true; (print_endline "Setting \"cil.addNestedScopeAttr\" to true"; set_bool "cil.addNestedScopeAttr" true; if (get_int "ana.malloc.unique_address_count") < 1 then ( From 6131273c1c95bf762749aa7a6a857fec09603def Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Tue, 31 Oct 2023 16:10:14 +0200 Subject: [PATCH 132/140] Separate memsafetySpecification autotuner and enable in svcomp conf Normal specification autotuner does other things we didn't want in SV-COMP. --- conf/svcomp.json | 3 ++- src/common/util/options.schema.json | 2 +- src/maingoblint.ml | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/conf/svcomp.json b/conf/svcomp.json index 913d43784b..342ac6f298 100644 --- a/conf/svcomp.json +++ b/conf/svcomp.json @@ -70,7 +70,8 @@ "congruence", "octagon", "wideningThresholds", - "loopUnrollHeuristic" + "loopUnrollHeuristic", + "memsafetySpecification" ] } }, diff --git a/src/common/util/options.schema.json b/src/common/util/options.schema.json index 400dde06dc..4d1b012701 100644 --- a/src/common/util/options.schema.json +++ b/src/common/util/options.schema.json @@ -544,7 +544,7 @@ "type": "array", "items": { "type": "string" }, "default": [ - "congruence", "singleThreaded", "specification", "mallocWrappers", "noRecursiveIntervals", "enums", "loopUnrollHeuristic", "arrayDomain", "octagon", "wideningThresholds" + "congruence", "singleThreaded", "specification", "mallocWrappers", "noRecursiveIntervals", "enums", "loopUnrollHeuristic", "arrayDomain", "octagon", "wideningThresholds", "memsafetySpecification" ] } }, diff --git a/src/maingoblint.ml b/src/maingoblint.ml index b5998df2d1..9e0b41fe3c 100644 --- a/src/maingoblint.ml +++ b/src/maingoblint.ml @@ -186,7 +186,7 @@ let handle_options () = check_arguments (); AfterConfig.run (); Sys.set_signal (GobSys.signal_of_string (get_string "dbg.solver-signal")) Signal_ignore; (* Ignore solver-signal before solving (e.g. MyCFG), otherwise exceptions self-signal the default, which crashes instead of printing backtrace. *) - if AutoTune.isActivated "specification" && get_string "ana.specification" <> "" then + if AutoTune.isActivated "memsafetySpecification" && get_string "ana.specification" <> "" then AutoTune.focusOnMemSafetySpecification (); Cilfacade.init_options (); handle_flags () From 4d6b570d6d3c20850fcbe0e95f86638e8595c78b Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Tue, 31 Oct 2023 16:29:10 +0200 Subject: [PATCH 133/140] Add type for SV-COMP multiproperty --- src/autoTune.ml | 21 ++++++++++++++------- src/util/loopUnrolling.ml | 7 ++++--- src/witness/svcomp.ml | 16 +++++++++------- src/witness/svcompSpec.ml | 9 +++++++++ src/witness/witness.ml | 10 +++++++--- 5 files changed, 43 insertions(+), 20 deletions(-) diff --git a/src/autoTune.ml b/src/autoTune.ml index b96848c841..c00564bce7 100644 --- a/src/autoTune.ml +++ b/src/autoTune.ml @@ -210,8 +210,8 @@ let activateLongjmpAnalysesWhenRequired () = enableAnalyses longjmpAnalyses; ) -let focusOnMemSafetySpecification () = - match Svcomp.Specification.of_option () with +let focusOnMemSafetySpecification (spec: Svcomp.Specification.t) = + match spec with | ValidFree -> (* Enable the useAfterFree analysis *) let uafAna = ["useAfterFree"] in print_endline @@ "Specification: ValidFree -> enabling useAfterFree analysis \"" ^ (String.concat ", " uafAna) ^ "\""; @@ -244,8 +244,11 @@ let focusOnMemSafetySpecification () = enableAnalyses memSafetyAnas) | _ -> () -let focusOnSpecification () = - match Svcomp.Specification.of_option () with +let focusOnMemSafetySpecification () = + List.iter focusOnMemSafetySpecification (Svcomp.Specification.of_option ()) + +let focusOnSpecification (spec: Svcomp.Specification.t) = + match spec with | UnreachCall s -> () | NoDataRace -> (*enable all thread analyses*) print_endline @@ "Specification: NoDataRace -> enabling thread analyses \"" ^ (String.concat ", " notNeccessaryThreadAnalyses) ^ "\""; @@ -255,6 +258,9 @@ let focusOnSpecification () = set_bool "ana.int.interval" true | _ -> () +let focusOnSpecification () = + List.iter focusOnSpecification (Svcomp.Specification.of_option ()) + (*Detect enumerations and enable the "ana.int.enums" option*) exception EnumFound class enumVisitor = object @@ -411,9 +417,10 @@ let congruenceOption factors file = let apronOctagonOption factors file = let locals = if List.mem "specification" (get_string_list "ana.autotune.activated" ) && get_string "ana.specification" <> "" then - match Svcomp.Specification.of_option () with - | NoOverflow -> 12 - | _ -> 8 + if List.mem Svcomp.Specification.NoOverflow (Svcomp.Specification.of_option ()) then + 12 + else + 8 else 8 in let globals = 2 in let selectedLocals = diff --git a/src/util/loopUnrolling.ml b/src/util/loopUnrolling.ml index 62d0f662f3..9a2f6c7b29 100644 --- a/src/util/loopUnrolling.ml +++ b/src/util/loopUnrolling.ml @@ -324,9 +324,10 @@ class loopUnrollingCallVisitor = object raise Found; | _ -> if List.mem "specification" @@ get_string_list "ana.autotune.activated" && get_string "ana.specification" <> "" then ( - match SvcompSpec.of_option () with - | UnreachCall s -> if info.vname = s then raise Found - | _ -> () + List.iter (function + | SvcompSpec.UnreachCall s -> if info.vname = s then raise Found + | _ -> () + ) (SvcompSpec.of_option ()) ); DoChildren ) diff --git a/src/witness/svcomp.ml b/src/witness/svcomp.ml index 22543d48a9..6d773f666b 100644 --- a/src/witness/svcomp.ml +++ b/src/witness/svcomp.ml @@ -8,7 +8,7 @@ module Specification = SvcompSpec module type Task = sig val file: Cil.file - val specification: Specification.t + val specification: Specification.multi module Cfg: MyCFG.CfgBidir end @@ -18,9 +18,10 @@ let task: (module Task) option ref = ref None let is_error_function f = let module Task = (val (Option.get !task)) in - match Task.specification with - | UnreachCall f_spec -> f.vname = f_spec - | _ -> false + List.exists (function + | Specification.UnreachCall f_spec -> f.vname = f_spec + | _ -> false + ) Task.specification (* TODO: unused, but should be used? *) let is_special_function f = @@ -30,9 +31,10 @@ let is_special_function f = | fname when String.starts_with fname "__VERIFIER" -> true | fname -> let module Task = (val (Option.get !task)) in - match Task.specification with - | UnreachCall f_spec -> fname = f_spec - | _ -> false + List.exists (function + | Specification.UnreachCall f_spec -> fname = f_spec + | _ -> false + ) Task.specification in is_svcomp && is_verifier diff --git a/src/witness/svcompSpec.ml b/src/witness/svcompSpec.ml index 4a3da23d9b..185f1fbf67 100644 --- a/src/witness/svcompSpec.ml +++ b/src/witness/svcompSpec.ml @@ -12,6 +12,8 @@ type t = | MemorySafety (* Internal property for use in Goblint; serves as a summary for ValidFree, ValidDeref and ValidMemtrack *) | ValidMemcleanup +type multi = t list + let of_string s = let s = String.strip s in let regexp_multiple = Str.regexp "CHECK( init(main()), LTL(G \\(.*\\)) )\nCHECK( init(main()), LTL(G \\(.*\\)) )\nCHECK( init(main()), LTL(G \\(.*\\)) )" in @@ -48,6 +50,8 @@ let of_string s = else failwith "Svcomp.Specification.of_string: unknown expression" +let of_string s: multi = [of_string s] + let of_file path = let s = BatFile.with_file_in path BatIO.read_all in of_string s @@ -77,3 +81,8 @@ let to_string spec = | ValidMemcleanup -> "valid-memcleanup", false in print_output spec_str is_neg + +let to_string spec = + match spec with + | [spec] -> to_string spec + | _ -> assert false (* TODO: aggregate *) diff --git a/src/witness/witness.ml b/src/witness/witness.ml index 9f5a3c1801..310717b9c3 100644 --- a/src/witness/witness.ml +++ b/src/witness/witness.ml @@ -303,7 +303,7 @@ struct val find_invariant: Node.t -> Invariant.t end - let determine_result entrystates (module Task:Task): (module WitnessTaskResult) = + let determine_result entrystates (module Task:Task) (spec: Svcomp.Specification.t): (module WitnessTaskResult) = let module Arg: BiArgInvariant = (val if GobConfig.get_bool "witness.enabled" then ( let module Arg = (val ArgTool.create entrystates) in @@ -338,7 +338,7 @@ struct ) in - match Task.specification with + match spec with | UnreachCall _ -> (* error function name is globally known through Svcomp.task *) let is_unreach_call = @@ -410,7 +410,7 @@ struct let module TaskResult = struct module Arg = PathArg - let result = Result.False (Some Task.specification) + let result = Result.False (Some spec) let invariant _ = Invariant.none let is_violation = is_violation let is_sink _ = false @@ -569,6 +569,10 @@ struct (module TaskResult:WitnessTaskResult) ) + let determine_result entrystates (module Task:Task): (module WitnessTaskResult) = + match Task.specification with + | [spec] -> determine_result entrystates (module Task) spec + | _ -> assert false (* TODO: aggregate *) let write entrystates = let module Task = (val (BatOption.get !task)) in From 3747556e90acdced4e01fc21e9c83107d10f93fc Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Tue, 31 Oct 2023 17:23:40 +0200 Subject: [PATCH 134/140] Remove special MemorySafety SV-COMP property, add full multiproperty handling --- src/autoTune.ml | 10 ---------- src/witness/svcomp.ml | 2 +- src/witness/svcompSpec.ml | 34 +++++++++++++++++----------------- src/witness/witness.ml | 27 ++++++++++++++++++++++----- 4 files changed, 40 insertions(+), 33 deletions(-) diff --git a/src/autoTune.ml b/src/autoTune.ml index c00564bce7..06347f3190 100644 --- a/src/autoTune.ml +++ b/src/autoTune.ml @@ -232,16 +232,6 @@ let focusOnMemSafetySpecification (spec: Svcomp.Specification.t) = ); print_endline @@ "Specification: ValidMemtrack and ValidMemcleanup -> enabling memLeak analysis \"" ^ (String.concat ", " memLeakAna) ^ "\""; enableAnalyses memLeakAna - | MemorySafety -> (* TODO: This is a temporary solution for the memory safety category *) - set_bool "ana.arrayoob" true; - (print_endline "Setting \"cil.addNestedScopeAttr\" to true"; - set_bool "cil.addNestedScopeAttr" true; - if (get_int "ana.malloc.unique_address_count") < 1 then ( - print_endline "Setting \"ana.malloc.unique_address_count\" to 1"; - set_int "ana.malloc.unique_address_count" 1; - ); - let memSafetyAnas = ["memOutOfBounds"; "memLeak"; "useAfterFree";] in - enableAnalyses memSafetyAnas) | _ -> () let focusOnMemSafetySpecification () = diff --git a/src/witness/svcomp.ml b/src/witness/svcomp.ml index 6d773f666b..736de0efae 100644 --- a/src/witness/svcomp.ml +++ b/src/witness/svcomp.ml @@ -45,6 +45,7 @@ struct | True | False of Specification.t option | Unknown + [@@deriving ord] let to_string = function | True -> "true" @@ -57,7 +58,6 @@ struct | ValidFree -> "valid-free" | ValidDeref -> "valid-deref" | ValidMemtrack -> "valid-memtrack" - | MemorySafety -> "memory-safety" (* TODO: Currently here only to complete the pattern match *) | ValidMemcleanup -> "valid-memcleanup" in "false(" ^ result_spec ^ ")" diff --git a/src/witness/svcompSpec.ml b/src/witness/svcompSpec.ml index 185f1fbf67..9bd5a35e3e 100644 --- a/src/witness/svcompSpec.ml +++ b/src/witness/svcompSpec.ml @@ -9,14 +9,13 @@ type t = | ValidFree | ValidDeref | ValidMemtrack - | MemorySafety (* Internal property for use in Goblint; serves as a summary for ValidFree, ValidDeref and ValidMemtrack *) | ValidMemcleanup +[@@deriving ord] type multi = t list let of_string s = let s = String.strip s in - let regexp_multiple = Str.regexp "CHECK( init(main()), LTL(G \\(.*\\)) )\nCHECK( init(main()), LTL(G \\(.*\\)) )\nCHECK( init(main()), LTL(G \\(.*\\)) )" in let regexp_single = Str.regexp "CHECK( init(main()), LTL(G \\(.*\\)) )" in let regexp_negated = Str.regexp "CHECK( init(main()), LTL(G ! \\(.*\\)) )" in if Str.string_match regexp_negated s 0 then @@ -32,25 +31,29 @@ let of_string s = UnreachCall f else failwith "Svcomp.Specification.of_string: unknown global not expression" - else if Str.string_match regexp_multiple s 0 then - let global1 = Str.matched_group 1 s in - let global2 = Str.matched_group 2 s in - let global3 = Str.matched_group 3 s in - let mem_safety_props = ["valid-free"; "valid-deref"; "valid-memtrack";] in - if (global1 <> global2 && global1 <> global3 && global2 <> global3) && List.for_all (fun x -> List.mem x mem_safety_props) [global1; global2; global3] then - MemorySafety - else - failwith "Svcomp.Specification.of_string: unknown global expression" else if Str.string_match regexp_single s 0 then let global = Str.matched_group 1 s in - if global = "valid-memcleanup" then + if global = "valid-free" then + ValidFree + else if global = "valid-deref" then + ValidDeref + else if global = "valid-memtrack" then + ValidMemtrack + else if global = "valid-memcleanup" then ValidMemcleanup else failwith "Svcomp.Specification.of_string: unknown global expression" else failwith "Svcomp.Specification.of_string: unknown expression" -let of_string s: multi = [of_string s] +let of_string s: multi = + List.filter_map (fun line -> + let line = String.strip line in + if line = "" then + None + else + Some (of_string line) + ) (String.split_on_char '\n' s) let of_file path = let s = BatFile.with_file_in path BatIO.read_all in @@ -77,12 +80,9 @@ let to_string spec = | ValidFree -> "valid-free", false | ValidDeref -> "valid-deref", false | ValidMemtrack -> "valid-memtrack", false - | MemorySafety -> "memory-safety", false (* TODO: That's false, it's currently here just to complete the pattern match *) | ValidMemcleanup -> "valid-memcleanup", false in print_output spec_str is_neg let to_string spec = - match spec with - | [spec] -> to_string spec - | _ -> assert false (* TODO: aggregate *) + String.concat "\n" (List.map to_string spec) diff --git a/src/witness/witness.ml b/src/witness/witness.ml index 310717b9c3..419185400c 100644 --- a/src/witness/witness.ml +++ b/src/witness/witness.ml @@ -507,8 +507,7 @@ struct ) | ValidFree | ValidDeref - | ValidMemtrack - | MemorySafety -> + | ValidMemtrack -> let module TrivialArg = struct include Arg @@ -570,9 +569,27 @@ struct ) let determine_result entrystates (module Task:Task): (module WitnessTaskResult) = - match Task.specification with - | [spec] -> determine_result entrystates (module Task) spec - | _ -> assert false (* TODO: aggregate *) + Task.specification + |> List.fold_left (fun acc spec -> + let module TaskResult = (val determine_result entrystates (module Task) spec) in + match acc with + | None -> Some (module TaskResult: WitnessTaskResult) + | Some (module Acc: WitnessTaskResult) -> + match Acc.result, TaskResult.result with + (* keep old violation/unknown *) + | False _, True + | False _, Unknown + | Unknown, True -> Some (module Acc: WitnessTaskResult) + (* use new violation/unknown *) + | True, False _ + | Unknown, False _ + | True, Unknown -> Some (module TaskResult: WitnessTaskResult) + (* both same, arbitrarily keep old *) + | True, True -> Some (module Acc: WitnessTaskResult) + | Unknown, Unknown -> Some (module Acc: WitnessTaskResult) + | False _, False _ -> failwith "multiple violations" + ) None + |> Option.get let write entrystates = let module Task = (val (BatOption.get !task)) in From 5093b5dd90a6ec7aca4c541e007c7d4f3025b707 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Tue, 31 Oct 2023 17:25:11 +0200 Subject: [PATCH 135/140] Fix witness determine_result for memsafety --- src/witness/witness.ml | 64 ++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 61 insertions(+), 3 deletions(-) diff --git a/src/witness/witness.ml b/src/witness/witness.ml index 419185400c..dd829dd9e2 100644 --- a/src/witness/witness.ml +++ b/src/witness/witness.ml @@ -505,8 +505,66 @@ struct in (module TaskResult:WitnessTaskResult) ) - | ValidFree - | ValidDeref + | ValidFree -> + let module TrivialArg = + struct + include Arg + let next _ = [] + end + in + if not !AnalysisState.svcomp_may_invalid_free then ( + let module TaskResult = + struct + module Arg = Arg + let result = Result.True + let invariant _ = Invariant.none + let is_violation _ = false + let is_sink _ = false + end + in + (module TaskResult:WitnessTaskResult) + ) else ( + let module TaskResult = + struct + module Arg = TrivialArg + let result = Result.Unknown + let invariant _ = Invariant.none + let is_violation _ = false + let is_sink _ = false + end + in + (module TaskResult:WitnessTaskResult) + ) + | ValidDeref -> + let module TrivialArg = + struct + include Arg + let next _ = [] + end + in + if not !AnalysisState.svcomp_may_invalid_deref then ( + let module TaskResult = + struct + module Arg = Arg + let result = Result.True + let invariant _ = Invariant.none + let is_violation _ = false + let is_sink _ = false + end + in + (module TaskResult:WitnessTaskResult) + ) else ( + let module TaskResult = + struct + module Arg = TrivialArg + let result = Result.Unknown + let invariant _ = Invariant.none + let is_violation _ = false + let is_sink _ = false + end + in + (module TaskResult:WitnessTaskResult) + ) | ValidMemtrack -> let module TrivialArg = struct @@ -514,7 +572,7 @@ struct let next _ = [] end in - if not !AnalysisState.svcomp_may_invalid_free && not !AnalysisState.svcomp_may_invalid_deref && not !AnalysisState.svcomp_may_invalid_memtrack then ( + if not !AnalysisState.svcomp_may_invalid_memtrack then ( let module TaskResult = struct module Arg = Arg From bb163a55ba1e06afcd267a02e521a4907f694db2 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Tue, 31 Oct 2023 19:13:04 +0200 Subject: [PATCH 136/140] Deduplicate Svcomp.is_error_function --- src/util/loopUnrolling.ml | 6 ++---- src/witness/svcomp.ml | 15 +++++++-------- 2 files changed, 9 insertions(+), 12 deletions(-) diff --git a/src/util/loopUnrolling.ml b/src/util/loopUnrolling.ml index 9a2f6c7b29..4ce8fc06b4 100644 --- a/src/util/loopUnrolling.ml +++ b/src/util/loopUnrolling.ml @@ -324,10 +324,8 @@ class loopUnrollingCallVisitor = object raise Found; | _ -> if List.mem "specification" @@ get_string_list "ana.autotune.activated" && get_string "ana.specification" <> "" then ( - List.iter (function - | SvcompSpec.UnreachCall s -> if info.vname = s then raise Found - | _ -> () - ) (SvcompSpec.of_option ()) + if Svcomp.is_error_function' info (SvcompSpec.of_option ()) then + raise Found ); DoChildren ) diff --git a/src/witness/svcomp.ml b/src/witness/svcomp.ml index 736de0efae..218f0716ae 100644 --- a/src/witness/svcomp.ml +++ b/src/witness/svcomp.ml @@ -16,12 +16,16 @@ end let task: (module Task) option ref = ref None -let is_error_function f = +let is_error_function' f spec = let module Task = (val (Option.get !task)) in List.exists (function | Specification.UnreachCall f_spec -> f.vname = f_spec | _ -> false - ) Task.specification + ) spec + +let is_error_function f = + let module Task = (val (Option.get !task)) in + is_error_function' f Task.specification (* TODO: unused, but should be used? *) let is_special_function f = @@ -29,12 +33,7 @@ let is_special_function f = let is_svcomp = String.ends_with loc.file "sv-comp.c" in (* only includes/sv-comp.c functions, not __VERIFIER_assert in benchmark *) let is_verifier = match f.vname with | fname when String.starts_with fname "__VERIFIER" -> true - | fname -> - let module Task = (val (Option.get !task)) in - List.exists (function - | Specification.UnreachCall f_spec -> fname = f_spec - | _ -> false - ) Task.specification + | fname -> is_error_function f in is_svcomp && is_verifier From 031dde1e9538335a0691462a946b571866c1674b Mon Sep 17 00:00:00 2001 From: Michael Schwarz Date: Wed, 1 Nov 2023 16:58:38 +0100 Subject: [PATCH 137/140] Add test for joinign thread array --- tests/regression/10-synch/28-join-array.c | 25 +++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 tests/regression/10-synch/28-join-array.c diff --git a/tests/regression/10-synch/28-join-array.c b/tests/regression/10-synch/28-join-array.c new file mode 100644 index 0000000000..99813b9810 --- /dev/null +++ b/tests/regression/10-synch/28-join-array.c @@ -0,0 +1,25 @@ +// PARAM: --set ana.activated[+] thread +#include + +int data = 0; +pthread_mutex_t data_mutex; + +void *thread(void *arg) { + pthread_mutex_lock(&data_mutex); + data = 3; // RACE! + pthread_mutex_unlock(&data_mutex); + return NULL; +} + +int main() { + pthread_t tids[2]; + + pthread_create(&tids[0], NULL, &thread, NULL); + pthread_create(&tids[1], NULL, &thread, NULL); + + pthread_join(tids[0], NULL); + + data = 1; //RACE! + + return 1; +} From 1d55756147f3dba8cc5f42a996ae3ffaf7c6dbce Mon Sep 17 00:00:00 2001 From: Michael Schwarz Date: Wed, 1 Nov 2023 16:59:08 +0100 Subject: [PATCH 138/140] threadAnalysis: Only add definite tids to set of mustJoined thread --- src/analyses/threadAnalysis.ml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/analyses/threadAnalysis.ml b/src/analyses/threadAnalysis.ml index 1e679a4707..1f6e9fabb3 100644 --- a/src/analyses/threadAnalysis.ml +++ b/src/analyses/threadAnalysis.ml @@ -61,7 +61,8 @@ struct s in match TS.elements (ctx.ask (Queries.EvalThread id)) with - | threads -> List.fold_left join_thread ctx.local threads + | [t] -> join_thread ctx.local t (* single thread *) + | _ -> ctx.local (* if several possible threads are may-joined, none are must-joined *) | exception SetDomain.Unsupported _ -> ctx.local) | _ -> ctx.local From f147d9bdd67fda7d77907631b643678eebe4284a Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 2 Nov 2023 10:05:22 +0200 Subject: [PATCH 139/140] Remove unused [@@deriving ord] on SV-COMP spec --- src/witness/svcomp.ml | 1 - src/witness/svcompSpec.ml | 1 - 2 files changed, 2 deletions(-) diff --git a/src/witness/svcomp.ml b/src/witness/svcomp.ml index 218f0716ae..eae97b1199 100644 --- a/src/witness/svcomp.ml +++ b/src/witness/svcomp.ml @@ -44,7 +44,6 @@ struct | True | False of Specification.t option | Unknown - [@@deriving ord] let to_string = function | True -> "true" diff --git a/src/witness/svcompSpec.ml b/src/witness/svcompSpec.ml index 9bd5a35e3e..66b3b83ac8 100644 --- a/src/witness/svcompSpec.ml +++ b/src/witness/svcompSpec.ml @@ -10,7 +10,6 @@ type t = | ValidDeref | ValidMemtrack | ValidMemcleanup -[@@deriving ord] type multi = t list From c42ec6b1e19eca1f1b899387a023d6505e285b7d Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Tue, 26 Sep 2023 18:09:51 +0300 Subject: [PATCH 140/140] Refactor Access.may_race with match --- src/domains/access.ml | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/src/domains/access.ml b/src/domains/access.ml index 8907ccbc32..3ba7aaee74 100644 --- a/src/domains/access.ml +++ b/src/domains/access.ml @@ -438,16 +438,13 @@ struct end -(* Check if two accesses may race and if yes with which confidence *) +(** Check if two accesses may race. *) let may_race A.{kind; acc; _} A.{kind=kind2; acc=acc2; _} = - if kind = Read && kind2 = Read then - false (* two read/read accesses do not race *) - else if not (get_bool "ana.race.free") && (kind = Free || kind2 = Free) then - false - else if not (MCPAccess.A.may_race acc acc2) then - false (* analysis-specific information excludes race *) - else - true + match kind, kind2 with + | Read, Read -> false (* two read/read accesses do not race *) + | Free, _ + | _, Free when not (get_bool "ana.race.free") -> false + | _, _ -> MCPAccess.A.may_race acc acc2 (* analysis-specific information excludes race *) (** Access sets for race detection and warnings. *) module WarnAccs =